TCP解包与封包

作者:追风剑情 发布于:2019-8-26 16:32 分类:C#

示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            //封装协议包
            ProtocolData pd = new ProtocolData();
            pd.WriteUInt32(1001);
            pd.WriteUTF8String("Hello World!");
            byte[] bytes = pd.EncapsulatePackage();

            //解析协议包
            PackageParser parser = new PackageParser();
            parser.OnPackageComplete += OnPackageComplete;
            parser.Receive(bytes);

            Console.ReadKey();
        }

        static void OnPackageComplete(ProtocolData pd)
        {
            Console.WriteLine("*** OnPackageComplete ***");
            Console.WriteLine("id={0}, message={1}", pd.ID, pd.Message);
        }
    }
}

/// <summary>
/// 数据包解析器
/// </summary>
public class PackageParser
{
    private ushort size = 0;
    private Stack<byte> receiveBuffer = new Stack<byte>();

    public Action<ProtocolData> OnPackageComplete;

    public void Receive(byte[] bytes)
    {
        if (bytes == null || bytes.Length == 0)
            return;
        for (int i = bytes.Length-1; i >= 0; i--)
            receiveBuffer.Push(bytes[i]);
        Parse();
    }

    private void Parse()
    {
        if (size == 0)
        {
            //用2个字节表示协议长度
            if (receiveBuffer.Count < 2)
                return;
            //Peek() 返回顶部元素,但不删除
            //Pop()  返回顶部元素,并删除
            byte[] size_bytes = new byte[] { receiveBuffer.Pop(), receiveBuffer.Pop() };
            size = BitConverter.ToUInt16(size_bytes, 0);
        }

        if (receiveBuffer.Count >= size)
        {
            //从缓冲区中提取出一个数据包
            byte[] bytes = new byte[size];
            for (int i = 0; i < size; i++)
            {
                bytes[i] = receiveBuffer.Pop();
            }
            size = 0;

            if (OnPackageComplete != null)
            {
                ProtocolData p = new ProtocolData(bytes);
                OnPackageComplete(p);
            }
        }
    }
}

/// <summary>
/// 协议数据
/// </summary>
public class ProtocolData
{
    //原始数据
    private byte[] bytes;
    //协议ID
    private uint id;
    //消息
    private string message;

    private List<byte> writeBuffer = new List<byte>();

    public ProtocolData() { }

    public ProtocolData(byte[] bytes)
    {
        this.bytes = bytes;
        this.Parse();
    }

    public uint ID
    {
        get { return id; }
    }

    public string Message
    {
        get { return message; }
    }

    private void Parse()
    {
        //从bytes中解析出具体字段
        this.id = ReadUInt32();
        this.message = ReadString(4);//跳过id
    }

    private uint ReadUInt32(int startIndex = 0)
    {
        uint i = BitConverter.ToUInt32(bytes, startIndex);
        return i;
    }

    private string ReadString(int startIndex = 0, int length = -1)
    {
        if (length == -1)
            length = bytes.Length - startIndex;

        //Copy
        byte[] bs = new byte[length];
        for (int i = 0; i < length; i++)
            bs[i] = bytes[startIndex + i];

        string s = System.Text.Encoding.UTF8.GetString(bs);
        return s;
    }

    public void WriteUInt32(uint i)
    {
        byte[] bytes = BitConverter.GetBytes(i);
        writeBuffer.AddRange(bytes);
    }

    public void WriteUTF8String(string s)
    {
        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(s);
        writeBuffer.AddRange(bytes);
    }

    // 封装协议包
    public byte[] EncapsulatePackage()
    {
        //内容长度
        ushort size = (ushort)writeBuffer.Count;
        List<byte> pb = new List<byte>();
        pb.AddRange(BitConverter.GetBytes(size));
        pb.AddRange(writeBuffer);
        return pb.ToArray();
    }
}

运行测试

1111.png

标签: C#

Powered by emlog  蜀ICP备18021003号   sitemap

川公网安备 51019002001593号