zoukankan      html  css  js  c++  java
  • 【转】Socket接收字节缓冲区

    原创本拉灯

    2014年04月16日 10:06:55

            我们接收Socket字节流数据一般都会定义一个数据包协议( 协议号,长度,内容),由于Socket接收数据是连续的,对方发两个包过来,Socket的 Recive事件有可能只触发一次或触发三次,也就是大家听到的粘包,为解决这个粘包,所以我们必要建一个字节缓冲区,将所有的接收到的字节流全放到这个缓冲区内 由这个缓冲区来分隔每个数据包的内容。

            这份代码也是为论坛某个人解决串口接收数据包时而写的。不多说了上代码:

    [csharp] view plain copy
     
    1. /// <summary>  
    2.    /// 字节缓冲器  
    3.    /// </summary>  
    4.    public class ByteQueue  
    5.    {  
    6.        private List<byte> m_buffer = new List<byte>();  
    7.        public bool Find()  
    8.        {  
    9.            if (m_buffer.Count == 0)  
    10.                return false;  
    11.            int HeadIndex = m_buffer.FindIndex(o => o == 0xAA);  
    12.   
    13.            if (HeadIndex == -1)  
    14.            {  
    15.                m_buffer.Clear();  
    16.                return false; //没找到AA  
    17.            }  
    18.   
    19.            else if (HeadIndex != 0) //不为开头移掉之前的字节  
    20.            {  
    21.                if (HeadIndex > 1)  
    22.                    m_buffer.RemoveRange(0, HeadIndex);  
    23.            }  
    24.   
    25.            int length= GetLength();  
    26.   
    27.            if (m_buffer.Count <length)  
    28.            {  
    29.                return false;  
    30.            }  
    31.   
    32.            int TailIndex = m_buffer.FindIndex(o => o == 0x55); //查找55的位置  
    33.   
    34.            if (TailIndex == -1)  
    35.            {  
    36.                //这一步为防止连发一个AA开头的包后,没发55,而又发了一个AA  
    37.                int head = m_buffer.FindLastIndex(o => o == 0xAA);  
    38.                if (head > -1)  
    39.                {  
    40.                    m_buffer.RemoveRange(0, head);  
    41.                }  
    42.                return false;  
    43.            }  
    44.            else if (TailIndex + 1 != length) //计算包尾是否与包长度相等  
    45.            {  
    46.                m_buffer.RemoveRange(0, TailIndex);  
    47.                return false;  
    48.            }  
    49.   
    50.            return true;  
    51.        }  
    52.   
    53.        /// <summary>  
    54.        /// 命令类型  
    55.        /// </summary>  
    56.        /// <returns></returns>  
    57.        public byte Cmd()  
    58.        {  
    59.            if (m_buffer.Count >= 2)  
    60.            {  
    61.                return m_buffer[1];  
    62.            }  
    63.            return 0;  
    64.        }  
    65.   
    66.        /// <summary>  
    67.        /// 序号  
    68.        /// </summary>  
    69.        /// <returns></returns>  
    70.        public byte Number()  
    71.        {  
    72.            if (m_buffer.Count >= 3)  
    73.            {  
    74.                return m_buffer[2];  
    75.            }  
    76.            return 0;  
    77.        }  
    78.   
    79.        /// <summary>  
    80.        /// 包长度  
    81.        /// </summary>  
    82.        /// <returns></returns>  
    83.        public int GetLength()  
    84.        {  
    85.            int len = 5;//AA 命令类型 序号 校验和 55  
    86.            if (m_buffer.Count >= 3)  
    87.            {  
    88.                switch (m_buffer[2]) //第三字节为序号  
    89.                {   
    90.                    case 0x00: //序号  
    91.                        return len + 16;  
    92.                    case 0x01: //序号  
    93.                        return len + 10;  
    94.                    case 0x02: //序号  
    95.                        return len + 12;  
    96.                }  
    97.            }  
    98.            return 0;  
    99.        }  
    100.        /// <summary>  
    101.        /// 提取数据  
    102.        /// </summary>  
    103.        public void Dequeue(byte[] buffer, int offset,int size)  
    104.        {  
    105.            m_buffer.CopyTo(0,buffer,offset,size);  
    106.            m_buffer.RemoveRange(0, size);  
    107.        }  
    108.   
    109.        /// <summary>  
    110.        /// 队列数据  
    111.        /// </summary>  
    112.        /// <param name="buffer"></param>  
    113.        public void Enqueue(byte[] buffer)  
    114.        {  
    115.            m_buffer.AddRange(buffer);  
    116.        }  
    117.    }  



     调用列子:

    [csharp] view plain copy
     
    1. private ByteQueue queue = new ByteQueue();  
    2. private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)  
    3.        {  
    4.            int len = serialPort1.BytesToRead;  
    5.            if (len > 0)  
    6.            {  
    7.                byte[] temp = new byte[len];  
    8.                serialPort1.Read(temp, 0, len);  
    9.                queue.Enqueue(temp);  
    10.                while (queue.Find()) //while可处理同时接收到多个AA ... 55 ,AA...55的包  
    11.                {  
    12.                    int length = queue.GetLength();  
    13.                    byte[] readBuffer = new byte[len];  
    14.                    queue.Dequeue(readBuffer, 0, length);  
    15.                    OnReceiveData(readBuffer); //<这里自己写一个委托吧就OK了  
    16.                }  
    17.   
    18.            }  
    19.   
    20.        }  


    上面的字节接收容器是用List来处理为方便进出字节后移除整个数据包的字节数据,当然更高效的应用byte[] 数组作成环形缓冲会好很多相对应的写法也会难一些,

  • 相关阅读:
    spring Pom jar包版本管理
    Liunx 命令整理
    Centos&Nginx
    docker-compose
    .net core MemoryCache缓存
    .net core 程序集帮助类
    .NET CORE API Swagger
    Spring Boot (1)
    SQL Server生成实体
    1、认识和安装MongoDB
  • 原文地址:https://www.cnblogs.com/laocainiao160622/p/8340991.html
Copyright © 2011-2022 走看看