我们的项目几乎离不开通讯,而有通讯必然涉及到通讯帧格式。在通讯帧格式的设计中,数据帧的字段设计常常被提及,但另一个的关键点——判尾,也是非常重要。在本帖,我总结了几种常用的通讯帧判尾方法,供大家参考。
使用特定的字符或字符序列作为帧的开始和结束标志。
1.ASCII控制字符如SOH(0x01, Start of Header,开始头)和EOH(0x04, End of Header,结束头)可以分别用来标识帧的开始和结束。
2.Modbus-Ascii模式,使用‘:’冒号做为帧首。使用'\r\n'回车换行为帧尾。
在帧的开始部分包含一个长度字段,该字段指定了帧中数据的长度。这样,接收端可以根据长度字段来确定帧的结束位置。这也是我们平时使用较频繁的帧头+payload的方式。举个例子:
typedef struct fram_hdr_s { uint16_t length; //其数值表示紧跟其后的数据长度 uint8_t type; uint8_t cksum; }fram_hdr_t;
三、定时器
接收端设置一个定时器,如果在一定时间内没有收到新的数据,则认为当前帧已经结束。这种方法通常用于面向非字符的协议。典型应用就是Modbus-RTU模式,其以3.5个字节间隔时间做为Timeout,判断帧结束。
四、断开链接方式
我在某篇文章上面读到,以网络连接为例,其分为发送链接与接收链接,当客户端断开发送链接时,即代表其已经完成本次数据帧的发送,因为还连接着接收链接,所以其可能正常接收服务端返回的数据。不过,这个方法我没有在我的实际应用中部署过,虽然听上去还是不错的。
五、总结帧尾的判断是通讯正常传递的基础,如果判尾失败,则会出现“粘包”现象,数据必然出现错误。
在本帖子中,分享了四种帧尾判断方式,针对不同的应用场景。大家在使用过程中,根据自己项目的实际需求来选择吧!