【轉】Socket接收字節緩衝區

原創本拉燈

2014年04月16日 10:06:55

        咱們接收Socket字節流數據通常都會定義一個數據包協議( 協議號,長度,內容),因爲Socket接收數據是連續的,對方發兩個包過來,Socket的 Recive事件有可能只觸發一次或觸發三次,也就是你們聽到的粘包,爲解決這個粘包,因此咱們必要建一個字節緩衝區,將全部的接收到的字節流全放到這個緩衝區內 由這個緩衝區來分隔每一個數據包的內容。數組

        這份代碼也是爲論壇某我的解決串口接收數據包時而寫的。很少說了上代碼:socket

[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.    }  



 調用列子:post

[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[] 數組做成環形緩衝會好不少相對應的寫法也會難一些,ui

相關文章
相關標籤/搜索