在客户端与服务端通信过程中,客户端通过TCP发送的数据包可能产生粘包。在读取的时候,当前的定义是包头添加数据包的长度,使用包头判断一个包的开始,通过流的当前位置读取包并截取要给完整的数据包,再把剩余的包返还到缓存数据区内。
MemoryStream ms = new MemoryStream(cache.ToArray());创建一个数据流;
BinaryReader br = new BinaryReader(ms);创建一个BinaryReader对象用来读取数据流;
public virtual int ReadInt32();从当前流中读取一个 4 字节有符号整数,并把流的当前位置往前移四个字节;
public virtual byte[] ReadBytes( int count );从当前流中读取指定数目的字节到一个字节数组中,并把流的当前位置往前移指定数目的字节。
流的当前位置的概念(ms.Position)
/// <summary>
/// 解析包,从缓冲区里取出一个完整的包
/// </summary>
/// <param name="cache"></param>
/// <returns></returns>
public static byte[] DecodePacket(ref List<byte> cache)
{
if (cache.Count < 4)
{
return null;
}
using (MemoryStream ms = new MemoryStream(cache.ToArray()))
{
using (BinaryReader br = new BinaryReader(ms))
{
//包的长度(ReadInt32:读取一个4字节的带符号整数,并把流的位置向前移4个字节)
int length = br.ReadInt32();
//包的长度减去流的当前位置,用于判断包是否完整
int remainLength = (int)(ms.Length - ms.Position);
if (length > remainLength)
{
return null;
}
//读取数据,并且流的位置position向前移动length长度的字节
byte[] data = br.ReadBytes(length);
//更新数据缓存
cache.Clear();
//流的总长度减去流的当前位置position,是剩余流的长度
int remainLengthAgain = (int)(ms.Length - ms.Position);
cache.AddRange(br.ReadBytes(remainLengthAgain));
return data;
}
}
}