基于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 }
时间: 2024-10-12 04:20:49

基于LWIP的Modbus TCP粘包处理的相关文章

TCP粘包问题分析和解决(全)

TCP通信粘包问题分析和解决(全) 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小.数据量小的数据,合并成一个大的数据块,然后进行封包.这样,接收端,就难于分辨出来了,必须提供科学的拆包机制. 对于UDP,不会使用块的合并优化算法,这样,实际上目前认为,是由于UDP支持的是一对多的模式,

Socket编程实践(5) --TCP粘包问题与解决

TCP粘包问题 因为TCP协议是基于字节流且无边界的传输协议, 因此非常有可能产生粘包问题, 问题描写叙述例如以下 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvempmMjgwNDQxNTg5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" /> 对于Host A 发送的M1与M2两个各10K的数据块, Host B 接收数据的方式不确定, 有以下

Netty中使用MessagePack时的TCP粘包问题与解决方案

[toc] Netty中使用MessagePack时的TCP粘包问题与解决方案 通过下面的实例代码来演示在Netty中使用MessagPack时会出现的TCP粘包问题,为了学习的连贯性,参考了<Netty权威指南>第7章中的代码,但是需要注意的是,书中并没有提供完整代码,提供的代码都是片段性的,所以我根据自己的理解把服务端的代码和客户端的代码写了出来,可以作为参考. 仍然需要注意的是,我使用的是Netty 4.x的版本. 另外我在程序代码中写了非常详细的注释,所以这里不再进行更多的说明. 在使

关于TCP粘包和拆包的终极解答

关于TCP粘包和拆包的终极解答 程序员行业有一些奇怪的错误的观点(误解),这些误解非常之流行,而且持有这些错误观点的人经常言之凿凿,打死也不相信自己有错,实在让人啼笑皆非.究其原因,还是因为这些错误观点所对应的正确观点不符合人的正常思维习惯,是扭曲人的直观感受的. 有两个错误观点非常之经典,一而再,再而三的出现,就跟韭菜一样,割不完,还越长越多.一是经典的"服务器最多65536个连接"误解,打开链接看介绍.另一个就是这里要讲的TCP"粘包"和"拆包&quo

TCP粘包问题

1. 问题背景: tcp是以流动的方式传输数据,没有边界的一段数据.像打开自来水管一样,连成一片,没有边界.传输的最小单位为一个报 文段(segment).tcp Header中有个Options标识位,常见的标识为mss(Maximum Segment Size)指的是:连接层每次传输的数据有个最大限制MTU(Maximum Transmission Unit),一般是1500比特,超过这个量要分成多个报文段,mss则是这个最大限制减去TCP的header,光是要传输的数据的大小,一般为146

netty 解决TCP粘包与拆包问题(二)

TCP以流的方式进行数据传输,上层应用协议为了对消息的区分,采用了以下几种方法. 1.消息固定长度 2.第一篇讲的回车换行符形式 3.以特殊字符作为消息结束符的形式 4.通过消息头中定义长度字段来标识消息的总长度 一.采用指定分割符解决粘包与拆包问题 服务端 1 package com.ming.netty.nio.stickpack; 2 3 4 5 import java.net.InetSocketAddress; 6 7 import io.netty.bootstrap.ServerB

tcp粘包问题(封包)

tcp粘包分析     http://blog.csdn.net/zhangxinrun/article/details/6721495 解决TCP网络传输“粘包”问题(经典)       http://blog.csdn.net/zhangxinrun/article/details/6721508 粘包出现原因:在流传输中出现,UDP不会出现粘包,因为它有消息边界(参考Windows 网络编程)1 发送端需要等缓冲区满才发送出去,造成粘包2 接收方不及时接收缓冲区的包,造成多个包接收 解决办

SOCKET TCP 粘包及半包问题

大家在使用SOCKET通信编程的时候,一般会采用UDP和TCP两种方式:TCP因为它没有包的概念,它只有流的概念,并且因为发送或接收缓冲区大小的设置问题,会产生粘包及半包的现象. 场景: 服务端向连续发送三个"HelloWorld"(三次消息无间隔),那么客户端接收到的情况会有以下三种: 1)HelloWorld HelloWorld HelloWorld (客户端接收三次) 2)HelloWorldHelloWor ldHelloWorld (客户端接收两次) 3)HelloWorl

Netty学习之TCP粘包/拆包

一.TCP粘包/拆包问题说明,如图 二.未考虑TCP粘包导致功能异常案例 按照设计初衷,服务端应该收到100条查询时间指令的请求查询,客户端应该打印100次服务端的系统时间 1.服务端类 package com.phei.netty.s2016042302; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitial