1. TCP 协议是一种基于数据流的协议
-
Socket的Receive方法只是把接收缓冲区的数据提取出来,当系统的接收缓冲区为空,Receive方法会被阻塞,直到里面有数据。
-
Socket的Send方法只是把数据写入到发送缓冲区里,具体的发送过程由操作系统负责。当操作系统的发送缓冲区满了,Send方法会阻塞
2.解决粘包问题的方法
一般有三种方法 可以解决粘包和半包问题,分别是
- 长度信息法: 指在每个数据包前面加上长度信
- 固定长度法: 每次都以相同的长度发送数据
- 结束符号法
一般 的游戏开发会在每个数据包前面加上长度字节, 以方便解析
2.1 发送数据代码
//点击发送按钮
public void Send(string sendStr)
{
//组装协议
byte [] bodyBytes = System.Text.Encoding.Default.GetBytes(sendStr);
Int16 len = (Int16)bodyBytes.Length;
byte[] lenBytes = BitConverter.GetBytes (len);
byte[] sendBytes = lenBytes.Concat(bodyBytes).ToArray( );
// 为了精简代码:使用同步Send
// 不考虑抛出异常
socket.Send(sendBytes);
}
2.2 定义一个缓冲区(readBuff)和一个指示缓冲区有效数据长度变量(buffCount)。
// 接收缓冲区
byte[] readBuff= new byte[1024];
// 接收缓 冲区的数据 长度
int buffcount = 0;
public void ReceiveCallback (IAsyncResult ar) {
Socket socket = (Socket) ar.AsyncState;
// 获取接收数据长度
int count = socket.EndReceive(ar);
buffCount += count;
.....
}
3. 大小端
3.1 使用Reverse()兼容大小端编码
如果使用BitConverter.GetBytes将数字转换成二进制数据,转换出来的数据有可能基于大端模式, 也有可能基于小端模式。
因为我们规定必须使用小端编码,一个简单的办法 是,判断系统是否是 小端编码的系统,如果不是,就使用Reverse() 方法将大端编码转换为 小端编码。以Send 为例,代码如下:
//点击发送按钮
public void Send ()
{
string sendStr = InputFeld.text;
// 组装协议
byte[| bodyBytes = System.Text.Encoding.Default.GetBytes (sendStr);
Int16 len = (Int16)bodyBytes.Length;
byte[] lenBytes = BitConverter.GetBytes (len);
//大 小 端编 码
if(!BitConverter.IsLittleEndian) {
Debug. Log (" [Send] Reverse lenBytes");
lenBytes.Reverse();
}
// 拼接字节
byte[] sendBytes = lenBytes.Concat(bodyBytes) .ToArray ( );
socket.Send(sendBytes);
}
3.2 手动还原数值
BitConverter. Toint16中根据系统大小端采用不同的编码方式,如果是小端编码,返回 的 是(pbyte) | ((pbyte+1)<< 8),如果是大端编码,返回的是(pbyte<< 8) | ((pbyte+1)。以小端为例,由于采用指针,(pbyte)指向缓冲区中指定位置的第1 个字节,(pbyte + 1)指向缓冲区中指定位置的第2个字节,((pbyte+1)<<8)表示左移8位,相当于乘以 256,返回的数字便是“第1个字节+第2字节256”,与4. 4.1节中介绍的步骤相同。
public void OnReceiveData ( ) {
// 消息长 度
if (buffCount <= 2)
return;
// 消息长度
Int16 bodyLength = (short) ((readBuff[1] << 8) | readBuff[0]);
Debug.Log ( "[Recv] bodyLength=" + bodyLength);
// 消息体、更新 缓冲区
// 消 息 处 理 、 继 续读 取 消 息
.....
}
readBuff[0] 代表缓冲区的第1 个字节,readBuff[1] 代 表 缓 冲 区 的 第 2 个 字 节, ( readBuff[1] < < 8 ) 代 表 将 缓 冲 区 第 2 个 字 节 的 数 据 乘 以 2 5 6 , 中 间的“|” 代表逻辑与,在这里等同于相加。
- 完整的ByteArray
ByteArray作为一种通用的byte