当前位置: 代码迷 >> C# >> socket怎么组包和解包发送
  详细解决方案

socket怎么组包和解包发送

热度:330   发布时间:2016-05-05 02:46:49.0
socket如何组包和解包发送
如题:采用面向稳定连接的ASCII流(STREM)方式,具体数据包格式如下所示:
字段名 长度(byte) 描述
头标志(0x02) 1
业务数据包长度 4
业务数据包 N
尾标志(0x03) 1
校验码 1 从包的第一个字节0x02开始,逐字节进行异或到包的结尾0x03,结果为最后校验字节。

各位大虾,帮忙说明一下该包的数据如何组包,发送给服务器端,本人对socket连接理解的不是很深,对于该包体的如何封装和解包

------解决思路----------------------
解包的时候一样,从第0个字节开始到倒数第二个字节循环异或,跟最后一个字节比较,如果相同,验证成功
------解决思路----------------------
引用:
Quote: 引用:

对于socket来说,它只认识byte[],socket负责把byte[]从源搬运到目标地
至于byte[]怎么解析,完全是业务层的事情;byte[] 如何构造、如何解析与socket传输无关

恩 我就是不太明白提交的数据如何按照规则“从包的第一个字节0x02开始,逐字节进行异或到包的结尾0x03,结果为最后校验字节。”解析。 可以给一个简单的数据的byte[]转换以及数据包的解析吗,本人实在不太明白上面的规则的含义。

处理思路不复杂,逐次从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;
        }
    }
}

  相关解决方案