基于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 }

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。