基於LWIP的Modbus TCP粘包處理


最近在做Modbus TCP時,碰到了TCP粘包問題,由於客戶端發送包的字節數較少並且速度也很快(10ms/次),導致了服務器端一下收到了好幾個包!

 

一般粘包情況存在以下幾種:

 

很多人在處理TCP粘包時,都會定義一個幀的數據結構,包含標識,長度,數據等信息。

本人認為Modbus TCP的幀結構就很好,能廣泛應用於電力,機房電源監控等領域也不是沒有道理的。

 

以下就Modbus TCP粘包問題作出處理,直接上代碼:

 1 //ADU和RTU合二為一結構體
 2 struct    adu_rtu      
 3         {  
 4         uint16    Tid;                    //事務標識符.    默認為0x0000.本例用作RS485串口號:0x0001->UART0、0x0002->UART1、0x0003->UART2、0x0004->UART3
 5         uint16    Pid;                    //協議標識符.    ModBus=0x0000.
 6         uint16    Len;                    //后續字節數.    高字節在前,低字節在后;包括單元標識符(從機地址)、功能碼、數據.
 7         uint8     data[256];              //協議數據幀.    實際為RTU幀。最大256個字節,包括從機地址、功能碼、數據,含CRC校驗碼.    
 8         };
 9 
10 
11 /*                                                                                                    
12 ******************************************************************************************************
13 **函數名稱:    void tcp_adu_process(struct pbuf *p)                                                  **
14 **函數描述:   處理TCP發來的ADU包,含TCP粘包處理(只針對上述第1種情況)                                       **
15 **參   數:    *p-------傳入的數據指針                                                                  **
16 **返   回:    無                                                                                     **
17 ******************************************************************************************************
18 */
19 void tcp_adu_process(struct pbuf *p)
20 {
21     uint8    buffer[300];
22     uint16    CRC_Temp, Tid, tot_len;
23     struct    adu_rtu     *aru;
24     
25     aru = p->payload;
26     tot_len = p->len;
27     
28     //ADU數據解析.並發送到指定串口.
29     while( ((HTONS(aru->Len)+6) <= tot_len) && (tot_len > 0) )                //adu_rtu幀頭為6個字節.
30         {
31         Tid = HTONS(aru->Tid);
32         if( (Tid>0)&&(Tid<5) )
33             {
34             memcpy(buffer, aru->data, HTONS(aru->Len));                       //復制數據.
35         
36             CRC_Temp = CRC16_bit(buffer, HTONS(aru->Len));
37             buffer[HTONS(aru->Len)]   = (uint8)CRC_Temp;                      //填充CRC校驗,低字節在前,高字節在后.
38             buffer[HTONS(aru->Len)+1] = (uint8)(CRC_Temp>>8);
39     
40             //發送數據到指定串口.
41             UART_IRQ_SendBytes(HTONS(aru->Tid)-1, buffer, HTONS(aru->Len)+2, ENABLE);
42             }
43         
44         //求出TCP剩余的總長度、下一個數據包的首地址.
45         tot_len -= HTONS(aru->Len)+6;
46         aru      = (struct adu_rtu *)((uint8 *)aru + HTONS(aru->Len) + 6);    //轉換成單字節指針后再加偏移地址.    
47         }    
48 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM