最近在做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 }
时间: 2024-10-12 04:20:49