美文网首页
Unity中Socket的使用

Unity中Socket的使用

作者: 双栖木 | 来源:发表于2018-01-18 14:37 被阅读0次

Socket

命名空间:System.Net.Sockets

服务器端:

    static void Main(string[] args)
    {
      // socket
      Socket listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      // bind
      IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
      IPEndPoint ipEP = new IPEndPoint(ipAdr, 1234);
      listenfd.Bind(ipEP);
      // listen
      listenfd.Listen(0);
      // 
      while (true)
      {
        // accept
        Socket connfd = listenfd.Accept();
        // receive
        byte[] readBuff = new byte[1024];
        int count = connfd.Receive(readBuff);
        string str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
        Console.WriteLine("[服务器接收:]" + str);
        // send
        byte[] bytes = System.Text.Encoding.Default.GetBytes("serv echo " + str);
        connfd.Send(bytes);
      }
    }

AddressFamily:地址簇,指明是使用IPv4还是IPv6
SocketType:套接字类型,Stream支持可靠、双向、基于连接的字节流,既不重复数据,也不保留边界
ProtocolType:协议
Socket.Bind(IPEndPoint):给Socket绑定IP和端口
Socket.Listen(int backlog):开启监听,等待客户端连接,参数指定队列中最多可容纳等待接受的连接数,0表示不限制
Socket.Accept:开启监听后,服务器调用Accept接受客户端连接
Receive:接收客户端数据,receive带有一个byte[]类型参数,它将存储接收到的数据,返回值指明接收到的数据的长度
Send:发送数据,接受一个byte[]类型的参数,指明要发送的内容

客户端:

Socket socket;
public InputField hostText;
public InputField portText;
public Text ipText;
public Text contentText;
byte[] readBuff = new byte[1024];
public void Connection()
  {    
    // socket
    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    // connect
    string host = hostText.text;
    int port = int.Parse(portText.text);
    socket.Connect(host, port);
    ipText.text = socket.LocalEndPoint.ToString();
    // send
    string str = "hello world";
    byte[] bytes = System.Text.Encoding.Default.GetBytes(str);
    socket.Send(bytes);
    // receive
    int count = socket.Receive(readBuff);
    str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
    contentText.text = str;
    socket.Close();
  }

粘包分包处理:

处理粘包分包的一种方法是在每个数据包前面加上长度字节。每次接受到数据后,先读取长度字节,如果缓冲区的数据长度大于要提取的字节数,则取出相应的字节,负责等待下一次数据接收。

  • Connect连接类:
public class Connect
  {
    public const int BUFFER_SIZE = 1024;
    public Socket socket;
    public bool isuse = false;
    public byte[] readBuff = new byte[BUFFER_SIZE];
    public int bufferCount = 0;
    public byte[] lenBytes = new byte[sizeof(int)];
    public int msgLength = 0;
    
    public Connect()
    {
      readBuff = new byte[BUFFER_SIZE];
    }
    public void Init(Socket socket)
    {
      this.socket = socket;
      isuse = true;
      bufferCount = 0;
    }
    public int BuffRemain()
    {
      return BUFFER_SIZE - bufferCount;
    }
    public string GetAdress()
    {
      if (!isuse)
        return "无法获取地址";
      return socket.RemoteEndPoint.ToString();
    }
    public void Close()
    {
      if (!isuse)
        return;
      Console.WriteLine("[断开链接]" + GetAdress());
      socket.Shutdown(SocketShutdown.Both);
      socket.Close();
      isuse = false;
    }
  }
  • ReceiveCb的粘包分包处理:ReceiveCb是接收数据的回调,它通过socket.EndReceive获取接收到数据的字节数count。connect.buffCount指向缓冲区的数据长度,接收数据缓冲区数据增加时,需要给buffCount加上count。
    ReceiveCb的实现如下:
public void ReceiveCb(IAsyncResult ar)
{
  Connect connect = (Connect)ar.AsyncState;
  try
  {
    int count = connect.socket.EndReceive(ar);
    if (count <= 0)
    {
      Console.WriteLine(connect.GetAdress()+"断开连接");
      connect.Close();
      return;
    }
    connect.bufferCount += count;
    ProcessData(connect);
        
    connect.socket.BeginReceive(connect.readBuff, connect.bufferCount, connect.BuffRemain(), SocketFlags.None, ReceiveCb, connect);
  }
  catch(Exception e)
  {
    Console.WriteLine(connect.GetAdress() + "断开连接");
    connect.Close();
  }
}
void ProcessData(Connect connect)
{
  if (connect.bufferCount < sizeof(int))
    return;
  // 消息长度
  Array.Copy(connect.readBuff, connect.lenBytes, sizeof(int));
  connect.msgLength = BitConverter.ToInt32(connect.lenBytes, 0);
  if (connect.bufferCount < connect.msgLength + sizeof(int))
    return;
  // 处理消息
  string str = System.Text.Encoding.UTF8.GetString(connect.readBuff, sizeof(int), connect.msgLength);
  Console.WriteLine("收到消息" + str);
  int count = connect.bufferCount - sizeof(int) - connect.msgLength;
  // 消除已处理的消息
  Array.Copy(connect.readBuff, sizeof(int) + connect.msgLength, connect.readBuff, 0, count);
  connect.bufferCount = count;
  if (connect.bufferCount > 0)
  {
    ProcessData(connect);
  }
}
  • 发送消息:需要组装消息长度和消息内容,然后一起发送
void Send(Connect connect,string str)
{
  byte[] bytes = System.Text.Encoding.UTF8.GetBytes(str);
  byte[] length = BitConverter.GetBytes(bytes.Length);
  byte[] sendbuff = length.Concat(bytes).ToArray();
  try
  {
    connect.socket.BeginSend(sendbuff, 0, sendbuff.Length, SocketFlags.None, null, null);
  }
  catch(Exception e)
  {
    Console.WriteLine("发送消息:" + e.Message);
  }
}

相关文章

网友评论

      本文标题:Unity中Socket的使用

      本文链接:https://www.haomeiwen.com/subject/shkwoxtx.html