• 高效的TCP数据拆包器



    高效的TCP数据拆包器 接收器,每秒拆1KB的包达到30万以上

        /// 数据同步协义数据接收器
        /// </summary>
        /// <remarks>
        /// 主要功能有
        /// 1.将一个TCPSocket的所有数据所有接收
        /// 2.解析协义
        /// 3.解析完毕后的协义调用 Handler通知外部处理
        /// 4.定义一个协义解析线程不停的解析协义
        /// </remarks>
        public class TCPReceiver : IDisposable
        {
            #region 构造函数
            /// <summary>
            /// 数据同步协义数据接收器 实例
            /// </summary>
            public TCPReceiver()
            {
    
    
            }
    
            /// <summary>
            /// 数据同步协义数据接收器 实例
            /// </summary>
            /// <param name="protocolhead">协议头</param>
            /// <param name="protocolfoot">协议尾</param>
            public TCPReceiver(byte[] protocolhead, byte[] protocolfoot = null)
            {
                //邦定包头,与包体
                PackageHead = protocolhead;
                PackageFoot = protocolfoot;
            }
    
            #endregion
    
            /// <summary>
            /// 最大单个协义体数据长度,默认10MB
            /// </summary>
            private int maxProtocolBinary = 1024 * 1024 * 10;
            /// <summary>
            /// 最大单个协义体数据长度
            /// </summary>
            public int MaxProtocolBinary
            {
                get { return maxProtocolBinary; }
                set { maxProtocolBinary = value; }
            }
    
            /// <summary>
            /// 是否正在执行
            /// </summary>
            public bool IsRuning { get; set; }
    
            private Task task = null;
            /// <summary>
            /// 当前处理解析协义的线程
            /// </summary>
            public Task PraseProtocolTask
            {
                get { return task; }
            }
    
            /// <summary>
            /// 接收数据处理事件
            /// </summary>
            public Action<byte[], Socket> ProtocolReceivedHandler
            {
                get;
                set;
            }
    
            /// <summary>
            /// 是从哪个节点接收的数据
            /// </summary>
            public Socket Handler
            {
                get;
                set;
            }
    
            #region 接收数据加入到队列
            /// <summary>
            /// 接收数据处理集合,默认开放1MB的空间
            /// </summary>
            // protected System.Collections.Generic.Queue<byte> byteQueue = new Queue<byte>(1024 * 1024);
    
            /// <summary>
            /// 默认开放500空间,100万次单纯加入用时95毫秒
            /// </summary>
            private Queue<byte[]> receiveByteArrayQueue = new Queue<byte[]>(500);
            /// <summary>
            /// 接入队列处理器
            /// </summary>
            protected Queue<byte[]> ReceiveByteArrayQueue
            {
                get { return receiveByteArrayQueue; }
            }
    
    #if DEBUG
            //private int cuount = 1;
    #endif
    
            /// <summary>
            /// 接收数据
            /// </summary>
            public void Receive(byte[] buff)
            {
    #if DEBUG
                //严重影响性能,会变慢1117倍
                // Console.WriteLine(buff.ToHex());
                //Console.WriteLine(buff.ByteArray2HexString());
                // Console.WriteLine("-----"+cuount++);
    #endif
    
                lock (receiveByteArrayQueue)
                {
                    //加入对像数据
                    receiveByteArrayQueue.Enqueue(buff);
                }
            }
            #endregion
    
            #region 线程控制
    
    
    
            /// <summary>
            /// 停止解析协义
            /// </summary>
            public void StopParseProtocol()
            {
                IsRuning = false;
                //throw new NotImplementedException("请编写代码,在线程停止后须要将缓存队列中的数据所有处理完毕");
                //在线程停止后须要将缓存队列中的数据所有处理完毕
                for (; receiveByteArrayQueue.Count > 0; )
                {
                    //处理数据
                    ProcessBytes();
                }
            }
            #endregion
    
    
            #region 解析协义数据
            /// <summary>
            /// 分包用包头
            /// </summary>
            private byte[] packageHead = new byte[] { 0x7e };//0x7e
    
    
            /// <summary>
            /// 分包用包头
            /// </summary>
            public byte[] PackageHead
            {
                get { return packageHead; }
                set
                {
                    if (value != null)
                    {
                        packageHead = value;
                    }
                }
            }
            /// <summary>
            /// 分包用包尾
            /// </summary>
            private byte[] packageFoot = new byte[] { 0x7e };
            /// <summary>
            /// 分包用包尾
            /// </summary>
            public byte[] PackageFoot
            {
                get { return packageFoot; }
                set
                {
                    if (value != null)
                    {
                        packageFoot = value;
    
                    }
                }
            }
    
    
    
    
            /// <summary>
            /// 用于处理数据协义的功能
            /// </summary>
            List<byte> bytes = new List<byte>();
    
            /// <summary>
            /// 默认开 3MB的数据接收缓冲区,假设超过3MB则数据会挂掉
            /// </summary>
            //private byte[] ByteBuff = null;
    
            /// <summary>
            /// 协义数据实体队列,已经进行拆包后的协义数据
            /// </summary>
            private Queue<byte[]> ProtocolEntityQueue = new Queue<byte[]>(500);
    
            /// <summary>
            /// 找到分包用包头
            /// </summary>
            bool FindPackageHead = false;
            /// <summary>
            /// 找包头的当着序号
            /// </summary>
            int findHeadindex = 0;
            /// <summary>
            /// 找包尾
            /// </summary>
            int findFootIndex = 0;
    
            /// <summary>
            /// 解析协义方法
            /// 之所以先所有放到一个query里是进行高速的接收
            /// 
            /// </summary>
            public void PraseProtocol()
            {
                IsRuning = true;
                while (IsRuning)
                {
                    ProcessBytes();
                }
            }
            /// <summary>
            /// 处理队列中的数据删除包头,包尾巴
            /// </summary>
            public void ProcessBytes()
            {
                byte[] arr = null;
                //開始解析数据
                //1.取出数据
                lock (receiveByteArrayQueue)
                {
                    if (receiveByteArrayQueue.Count > 0)
                    {
                        arr = receiveByteArrayQueue.Dequeue();
                    }
                }
                if (arr != null)
                {
                    //锁处理
                    lock (bytes)
                    {
                        //此协义数据中的协义数据索引
                        // List<int> ints = new List<int>();
    
                        //2.将数据进行包查找
                        //開始从队列中取数据
                        for (int k = 0; k < arr.Length; k++)
                        {
                            //队列有数据
                            byte b = arr[k];
                            //假设超过最大接收字节数
                            if (maxProtocolBinary <= bytes.Count)
                            {
                                bytes.Clear();
                            }
                            //加入到对像集合
                            bytes.Add(b);
                            //3.从集合的前面開始取数据.找包头,进行拆包
                            #region 找包头
                            //等于包数据
                            if (packageHead.Length > 0 && b == packageHead[findHeadindex] && !FindPackageHead)
                            {
    
                                //包头找完
                                if (findHeadindex == packageHead.Length - 1)
                                {
    
                                    //ints.Add(k);
                                    System.Threading.Interlocked.Exchange(ref findHeadindex, 0);
                                    if (!FindPackageHead)
                                    {
                                        FindPackageHead = true;
                                    }
                                    //这里取一个完整包
                                    byte[] byteFarm = bytes.Take(bytes.Count - packageHead.Length).ToArray();
                                    //假设是有效的数据
                                    if (byteFarm.Length > packageHead.Length)
                                    {
                                        lock (ProtocolEntityQueue)
                                        {
                                            ProtocolEntityQueue.Enqueue(byteFarm);
                                        }
                                        //開始从 bytes 中移除数据
                                        bytes.Clear();
                                        //加入包头
                                        bytes.AddRange(packageHead);
                                    }
                                    //包头找完则找下一字节
                                    continue;
                                }
                                else
                                {
                                    System.Threading.Interlocked.Increment(ref findHeadindex);
                                }
                            }
                            else
                            {
                                System.Threading.Interlocked.Exchange(ref findHeadindex, 0);
                                //findHeadindex = 0;
                                if (!FindPackageHead && packageHead.Length == 0)
                                {
                                    FindPackageHead = true;
                                }
                            }
                            #endregion
    
                            #region 找包尾
    
                            if (packageFoot != null && packageFoot.Length > 0 && FindPackageHead)
                            {
                                if (b == packageFoot[findFootIndex])
                                {
                                    //包尾找完
                                    if (findFootIndex == packageFoot.Length - 1)
                                    {
                                        //删除包尾字节,可能会包括包头字节
                                          //byte[] byteFarm = bytes.Take(bytes.Count - packageFoot.Length).ToArray();
                                        byte[] byteFarm = bytes.ToArray();
                                        //跳过包头字节,包尾字节
                                        //byte[] byteFarm = bytes.Skip(packageHead.Length).Take(bytes.Count - (packageFoot.Length + packageHead.Length)).ToArray();
                                        //假设是有效的数据
                                        if (byteFarm.Length >= packageFoot.Length)
                                        {
                                            lock (ProtocolEntityQueue)
                                            {
                                                ProtocolEntityQueue.Enqueue(byteFarm);
                                            }
                                            //開始从 bytes 中移除数据
                                            bytes.Clear();
                                        }
                                        FindPackageHead = false;
                                        //包尾找完则找下一字节
                                        continue;
                                    }
                                    else
                                    {
                                        System.Threading.Interlocked.Increment(ref findFootIndex);
                                    }
                                }
                                else
                                {
                                    System.Threading.Interlocked.Exchange(ref findFootIndex, 0);
                                    //findFootIndex = 0;
    
                                }
                            }
    
                            #endregion
    
                        }
                    }
                    //4.又一次组成一个byte[] 进行数据解析
                    lock (ProtocolEntityQueue)
                    {
                        if (ProtocolEntityQueue.Count > 0)
                        {
                            //循环所有接收到的数据包
                            for (; ProtocolEntityQueue.Count > 0; )
                            {
    
                                //取取删除尾巴的的数据
    
    
                                //解析协议数据
                                byte[] bytearr = ProtocolEntityQueue.Dequeue();
    
    
                                //数据要大于分包的长度
                                if (bytearr.Length >= packageFoot.Length && bytearr.Length >= packageHead.Length)
                                {
                                    ProtocolReceivedHandler.Invoke(bytearr, Handler);
                                }
                            }
                        }
                    }
                }
                else
                {
                    //停止执行
                    IsRuning = false;
                    //System.Threading.Thread.Sleep(5);
                }
            }
    
            #endregion
    
            /// <summary>
            /// 析构方法
            /// </summary>
            public void Dispose()
            {
                StopParseProtocol();
            }
    
    
        }


    用法 

    TCPReceiver   rece = new  TCPReceiver();

    //将接收到的数据增加处理

    rece .Receive(buff);


    另起一个线程进行处理

    while(true)

    {

    rece .PraseProtocol();

    }


  • 相关阅读:
    wp7 db
    wp7 webpair
    wp7 弹出动画
    wp7 执行独立存储任务
    黑马程序员第二阶段JAVA网络编程第24天
    黑马程序员第二阶段图形用户界面第22天(1)
    黑马程序员第三阶段Java基础加强第26天
    黑马程序员第三阶段Java基础加强第25天
    黑马程序员第二阶段Java高级IO第21天
    黑马程序员第二阶段JAVA网络编程第23天
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/6951663.html
Copyright © 2020-2023  润新知