如题:采用面向稳定连接的ASCII流(STREM)方式,具体数据包格式如下所示:
字段名 长度(byte) 描述
头标志(0x02) 1
业务数据包长度 4
业务数据包 N
尾标志(0x03) 1
校验码 1 从包的第一个字节0x02开始,逐字节进行异或到包的结尾0x03,结果为最后校验字节。
各位大虾,帮忙说明一下该包的数据如何组包,发送给服务器端,本人对socket连接理解的不是很深,对于该包体的如何封装和解包
------解决思路----------------------
解包的时候一样,从第0个字节开始到倒数第二个字节循环异或,跟最后一个字节比较,如果相同,验证成功
------解决思路----------------------
处理思路不复杂,逐次从byte[]中读取数据,进行验证就可以。
以验证包头为例
private byte ReadByte(byte[] inputData, int offset)
{
return ((byte)inputData[offset]);
}
private int ReadInt32(byte[] inputData, int offset)
{
int num = 4 + offset;
return (((inputData[num - 4] << 24
------解决思路----------------------
(inputData[num - 3] << 16))
------解决思路----------------------
(inputData[num - 2] << 0x8))
------解决思路----------------------
(inputData[num - 1]));
}
/// <summary>
/// 检查接收的byte[]是否是合法包
/// </summary>
/// <returns></returns>
private int CheckReceivedBuffer(byte[] dataBuffer)
{
int nFlag = -1;
if (dataBuffer != null && dataBuffer.Length > 0)
{
//接收到的真实长度
int readBytesLen = dataBuffer.Length;
//读取包头,验证标识
byte headFlag = ReadByte(dataBuffer, 0); //头标志
if( headFlag != 0x02)
{
return -1;
}
int packetLen = ReadInt32(dataBuffer, 1);
//如果包头数据正常
if(readBytesLen >= packetLen + 7)
{
//parse data
nFlag = 0;
}
}
return nFlag;
}
------解决思路----------------------
具体实现方法可以有很多,一种比较直观,也比较健壮的方式就是用BinaryReader(优点在于分包很容易)。
比如下例,在Stream基础上组包和解包(方便单元测试)。发送和接收时,换入TcpClient.GetStream就可以了:
class Program
{
static void Main(string[] args)
{
TcpClient client = ...;
byte[] data1 = ...;
// 发送
Write(client.GetStream(), data1);
// 接受
byte[] data2 = Read(client.GetStream());
}
static void 单元测试()
{
using (MemoryStream stream = new MemoryStream())
{
Write(stream, Encoding.UTF8.GetBytes("nihao"));
Write(stream, new byte[] { 8, 8, 8 });
Write(stream, Encoding.UTF8.GetBytes("人有多大胆,地有多大产!"));
stream.Position = 0;
string msg1 = Encoding.UTF8.GetString(Read(stream)); // nihao
byte[] b888 = Read(stream); // {8,8,8}
string msg2 = Encoding.UTF8.GetString(Read(stream)); // 人有多大胆,地有多大产!
}
}
static void Write(Stream stream, byte[] data)
{
using (var writer = new BinaryWriter(stream, Encoding.UTF8, leaveOpen:true))
{
byte checksum = 0x2;
checksum ^= BitConverter.GetBytes(data.Length).Aggregate((s,b) => (byte)(s ^ b));
checksum ^= data.Aggregate((s, b) => (byte)(s ^ b));
checksum ^= 0x3;
writer.Write((byte)0x2); // 头标志
writer.Write(data.Length); // 业务数据包长度
writer.Write(data); // 业务数据包
writer.Write((byte)0x3); // 尾标志
writer.Write(checksum); // 校验码
writer.Flush();
}
}
static byte[] Read(Stream stream)
{
using (var reader = new BinaryReader(stream, Encoding.UTF8, leaveOpen: true))
{
if (reader.ReadByte() != 0x2) throw new InvalidOperationException("不正确头标志");
int dataLength = reader.ReadInt32();
byte[] data = reader.ReadBytes(dataLength);
if (reader.ReadByte() != 0x3) throw new InvalidOperationException("不正确尾标志");
byte checksum = 0x2;
checksum ^= BitConverter.GetBytes(data.Length).Aggregate((s, b) => (byte)(s ^ b));
checksum ^= data.Aggregate((s, b) => (byte)(s ^ b));
checksum ^= 0x3;
if (reader.ReadByte() != checksum) throw new InvalidOperationException("不正确校验码");
return data;
}
}
}