串口、网口等自定义通信协议的问题

2023-05-16

自定义通信协议的问题

  • 一、串口
    • 1、通信分为网络通信和串口通信
    • 2、协议格式
    • 3、协议设计
    • 4、代码实现
  • 二、网口
    • 1、TCP粘包与拆包
      • * 包的划分
      • * 出现TCP粘包的原因
      • * 粘包与拆包的几种情况
      • * 常见的粘包与拆包解决方案
    • 2、为什么UDP没有粘包?
    • 3、TCP、UDP数据发送区别
    • 4、为什么要等待2MSL
    • 5、TCP为什么会丢包?
    • 6、如何解决TCP丢包问题?
    • 7、UDP丢包的原因
    • 8、解决UDP丢包的问题

一、串口

1、通信分为网络通信和串口通信

a) 网络通信只用于文件数据的传输,网络连接中,PC为服务端,控制器为客户端;只有一个包接收处理完成命令:“0xFF 0x55”
b) 串口通信主要完成命令、状态、数据等传输,后续说的协议主要是针对串口协议

2、协议格式

在这里插入图片描述
【注】:所有多字节数据,协议中在低字节位置的字节为该数据的低位,如2字节数据,在协议中有Data[0]、Data[1]组成,那么,该数据value为:
Value = (((u16) Data[1]) << 8) + Data[0];
【注】:文档中所有数据,如开头为0x的都为16进制数据,否则为十进制数据。

3、协议设计

主功能ID说明:

  1. 操作控制类的主命令范围:0x01~0x3F
  2. 参数设置或获取类的主命令范围:0x40~0x7F
  3. 系统状态类的主命令范围:0x80~0xBF
  4. 调试类的主命令范围:0xE0~0xEF

子命令ID说明:

  1. MCU上传的子命令的最高位为1
  2. MCU上传每个主命令下的子命令取值范围为:0x81~0xFE
  3. PC下发的子命令的最高位为0
  4. PC下发每个主命令下的子命令取值范围为:0x01~0x7E

应答命令说明:

  1. 应答的主命令跟接收到的命令一致
  2. 应答的子命令的低七位跟接收到的一致,最高位跟根据上MCU应答还是PC应答决定,MCU应答则最高位为1,PC应答则最高位为0
  3. 需要由超时应答机制,一旦超时需要重新发送一次,最多重复发送3次;超时时间为500ms

4、代码实现

1、消息数据发送

  1. 通过串口直接发送每个字节
  2. 通过消息队列发送,用一个buf装下消息,然后“打包”到消息队列,通过FIFO发送出去
  3. 用“结构体”代替“数组SendBuf”方式

2、消息数据接收(中断、轮询)

  1. 常规中断接收
  2. 增加超时检测:用多余的MCU定时器做一个超时计数的处理,接收到一个数据,开始计时,超过1ms没有接收到下一个数据,就丢掉这一包(前面接收的)数据。
  3. 接收也可以用结构体的方式

二、网口

1、TCP粘包与拆包

* 包的划分

TCP是面向字节流的协议,就是没有界限的一串数据,本没有“包”的概念,“粘包”和“拆包”一说是为了有助于形象地理解这两种现象。
操作系统在发送TCP数据时,会通过缓冲区来进行优化,例如缓冲区为1024个字节大小。

  • 如果一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送,这就形成了粘包问题。
  • 如果一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是拆包。

* 出现TCP粘包的原因

在这里插入图片描述

* 粘包与拆包的几种情况

1、正常的理想情况,两个包恰好满足TCP缓冲区的大小或达到TCP等待时长,分别发送两个包;
2、粘包:两个包较小,间隔时间短,发生粘包,合并成一个包发送;
3、拆包:一个包过大,超过缓存区大小,拆分成两个或多个包发送;
4、拆包和粘包:Packet1过大,进行了拆包处理,而拆出去的一部分又与Packet2进行粘包处理。

* 常见的粘包与拆包解决方案

(1)发送方
关闭Nagle算法,使用TCP_NODELAY选项来关闭算法。
(2)接收方
接收方没有办法来处理粘包现象,只能将问题交给应用层来处理。
(3)应用层
1、发送端将每个包都封装成固定的长度,比如100字节大小。如果不足100字节,可通过补0来进行填充到指定长度。对于高并发、大流量的系统来说,每个数据包都不应该传输多余的数据(所以补齐的方式不可取)
2、发送端在每个包的末尾使用固定的分隔符,例如\r\n。如果发生拆包需要等待多个包发送过来之后再找到其中的\r\n进行合并;例如,FTP协议
3、将消息分为头部和消息体,头部中保存整个消息的长度,只有读到足够长的消息之后才算读到了一个完整的消息;(最常用)

2、为什么UDP没有粘包?

粘包与拆包问题在数据链路层、网络层以及传输层都有可能发生。一般发生在传输层,由于UDP有消息保护边界,接收方一次只接受一条独立的信息,不会发生粘包拆包问题,因此粘包拆包问题只发生在TCP协议中。
在UDP协议的接收端,采用了链式结构来记录每一个到达的UDP包,这样接收端应用程序一次recv只能从socket接收缓冲区中读出一个数据包。也就是说,发送端send了几次,接收端必须recv几次(无论recv时指定了多大的缓冲区)。

3、TCP、UDP数据发送区别

举个例子:有三个数据包,大小分别为2k、4k、6k

  • 采用UDP发送的话,不管接受方的接收缓存有多大,我们必须要进行至少三次以上的发送才能把数据包发送完,
  • 使用TCP协议发送的话,我们只需要接受方的接收缓存有12k的大小,就可以一次把这3个数据包全部发送完毕。

4、为什么要等待2MSL

1、一定出现在【主动关闭连接请求端】----TIME_WAIT
2、保证最后一个ACK能成功被对端接收。(等待期间,对端没有收到我的ACK,对端会再次发送FIN请求)
3、保证这次连接的重复数据段从网络中消失,实现TCP全双工连接的可靠释放

5、TCP为什么会丢包?

1、TCP是基于不可靠的网络实现可靠传输,肯定会存在丢包问题
2、如果在通信过程中,发现缺少数据或者丢包,那么最大的可能性是程序发送过程或者接收过程出现问题。

6、如何解决TCP丢包问题?

为了满足TCP协议不丢包,TCP协议有如下规定:

1、数据分片:发送端对数据进行分片,接收端要对数据进行重组,由TCP确定分片的大小并控制分片和重组。
2、到达确认:接收端接收到分片数据时,根据分片数据号向发送端发送一个确认
3、超时重发:发送方在发送分片时设置超时定时器,如果在定时器超时之后没有收到相应的确认,重发分片数据。
4、滑动窗口:TCP连接的每一方的接收缓冲空间固定,接收端只允许另一端发送接收端缓冲区所能接纳的数据,TCP在滑动窗口的基础上提供流量控制,防止较快主机致使较慢主机的缓冲区溢出。
5、失序处理:作为IP数据报来传输的TCP分片到达时可能会失序,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
6、重复处理:作为IP数据报来传输的TCP分片会发生重复,TCP的接收端必须丢弃重复的数据。
7、数据校验:TCP将保持它首部和数据的校验和,这是一个端到端的校验和,目的是检测数据在传输过程中的任何变化。如果收到分片的校验或有差错,TCP将丢弃这个分片,并不确认收到此报文段导致对端超时并重发。

7、UDP丢包的原因

  1. 接收端处理时间过长导致丢包
    调用recv方法接收端收到数据后,处理数据花了一些时间,处理完后再次调用recv方法,在这二次调用间隔里,发过来的包可能丢失。对于这种情况可以修改接收端,将包接收后存入一个缓冲区,然后迅速返回继续recv。
  2. 发送的包巨大丢包
    虽然send方法会帮你做大包切割成小包发送的事情,但包太大也不行。例如超过50K的一个udp包,不切割直接通过send方法发送也会导致这个包丢失。这种情况需要切割成小包再逐个send
  3. 发送的包较大,超过接收者缓存导致丢包
    包超过mtu size数倍,几个大的udp包可能会超过接收者的缓冲,导致丢包。这种情况可以设置socket接收缓冲。以前遇到过这种问题,我把接收缓冲设置成64K就解决了。
  4. 发送的包的频率太快
    虽然每个包的大小都小于mtu size 但是频率太快,例如40多个mut size的包连续发送中间不sleep,也有可能导致丢包。这种情况也有时可以通过设置socket接收缓冲解决,但有时解决不了。所以在发送频率过快的时候还是考虑sleep一下吧。
  5. 局域网内不丢包,公网上丢包
    这个问题我也是通过切割小包并sleep发送解决的。如果流量太大,这个办法也不灵了。总之udp丢包总是会有的,如果出现了用我的方法解决不了,还有这个几个方法: 要么减小流量,要么换tcp协议传输,要么做丢包重传的工作

8、解决UDP丢包的问题

  1. 发送频率过高导致丢包
    很多人会不理解发送速度过快为什么会产生丢包,原因就是UDP的SendTo不会造成线程阻塞,也就是说,UDP的SentTo不会像TCP中的SendTo那样,直到数据完全发送才会return回调用函数,UDP不保证当执行下一条语句时数据是否被发送。(SendTo方法是异步的)这样,如果要发送的数据过多或者过大,那么在缓冲区满的那个瞬间要发送的报文就很有可能被丢失。至于对“过快”的解释,作者这样说:“A few packets a second are not an issue; hundreds or thousands may be an issue.”(一秒钟几个数据包不算什么,但是一秒钟成百上千的数据包就不好办了)。 要解决接收方丢包的问题很简单,首先要保证程序执行后马上开始监听(如果数据包不确定什么时候发过来的话),其次,要在收到一个数据包后最短的时间内重新回到监听状态,其间要尽量避免复杂的操作(比较好的解决办法是使用多线程回调机制)。

  2. 报文过大丢包
    至于报文过大的问题,可以通过控制报文大小来解决,使得每个报文的长度小于MTU。以太网的MTU通常是1500 bytes,其他一些诸如拨号连接的网络MTU值为1280 bytes,如果使用speaking这样很难得到MTU的网络,那么最好将报文长度控制在1280 bytes以下。

  3. 发送方丢包
    发送方丢包:内部缓冲区(internal buffers)已满,并且发送速度过快(即发送两个报文之间的间隔过短);

  4. 接收方丢包:Socket未开始监听; 虽然UDP的报文长度最大可以达到64 kb,但是当报文过大时,稳定性会大大减弱。这是因为当报文过大时会被分割,使得每个分割块(翻译可能有误差,原文是fragmentation)的长度小于MTU,然后分别发送,并在接收方重新组合(reassemble),但是如果其中一个报文丢失,那么其他已收到的报文都无法返回给程序,也就无法得到完整的数据了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

串口、网口等自定义通信协议的问题 的相关文章

随机推荐

  • socket编程二十六:基于UDP的服务器端和客户端

    前面的文章中我们给出了几个 TCP 的例子 xff0c 对于 UDP 而言 xff0c 只要能理解前面的内容 xff0c 实现并非难事 UDP中的服务器端和客户端没有连接 UDP 不像 TCP xff0c 无需在连接状态下交换数据 xff0
  • 下载高清电影的必须收藏的网站

    下载高清电影的必须收藏的网站 Posted 2012 12 06 分类 生活范儿 电影 生活范儿 电影 CHD 虽然蓝光推出 xff0c 但是高清已经势不可挡 xff0c 动辄几G甚至几十G一部的电影冲击着我们的视觉 xff0c 也考验着我
  • 电赛总结|电赛注意事项

    电赛总结 赛前 1 准备模块非常重要 如果没有提前准备模块 xff0c 在赛中也是在想尽办法买模块 xff0c 只是花更多的钱和运费等 xff0c 也不会去自己搭 所以赛前一定要准备模块 常见模块 降压模块 xff0c 升压稳压模块 xff
  • Putty使用教程

    Putty作为免费且开源的老牌 SSH 客户端 xff0c PuTTY 经常用于 Windows 下连接管理远程服务器 为方便刚接触 VPS 的新手参考使用 xff0c 本文配合截图介绍 PuTTY 的基础用法及一些设置技巧 xff0c 希
  • #Python实现话题的发布与订阅

    Python实现话题的发布与订阅 首先我们的先了解ROS文件系统的基本框架 xff0c 如下图所示 xff1a 由上图可知 xff0c py文件放在工作包里面的scripts文件夹内 xff0c 所以 xff0c 整活 xff01 1 在工
  • #创建自定义topic

    创建自定义topic 前面我们学了用C 43 43 和Python创建发布者与订阅者 xff0c 这次我们创建自定义的话题 xff0c 其实同C 43 43 实现topic差不多 xff0c 都是编写 cpp文件 步骤有点多且繁琐 xff0
  • #使用TF实现海龟机器人跟随

    使用TF实现海龟机器人跟随 昨天粗略地讲解了一会儿TF变换 xff0c 用的是ROS系统中自带的功能包实现小海龟跟随的功能 xff08 具体见 初识TF变换 xff09 今天我们将用自己编写节点的方式实现小海龟跟随的功能 xff0c 并且
  • #创建虚拟机器人URDF模型

    创建虚拟机器人URDF模型 题外话 xff1a 作业发布已有一两天了 xff0c 之所以今天才编辑这篇博客 xff0c 是因为我也遇到问题了 xff0c 现在以及解决了 xff08 小细节 xff1a 创建功能包之前先编译工作空间确保里面已
  • # gazebo 仿真

    gazebo 仿真 1 给 base link 添加惯性 xff0c 碰撞以及 gazebo 属性 在路径xqrobot description urdf xacro 件夹下新建 件夹 gazebo xff0c 并在 gazebo 件下创建
  • #Gmapping

    Gmapping 开始之前先安装两个功能包 xff0c 命令如下 xff1a sudo apt span class token operator span get install ros span class token operator
  • #navigation

    navigation 1 安装相关依赖 sudo apt span class token operator span get install ros span class token operator span kinetic span
  • # Qt_day1

    Qt day1 1 项目框架 span class token macro property span class token directive hash span span class token directive keyword i
  • ros先订阅后发布 无法收到消息的解决办法

    现象 今天遇到的问题是 使用的是Ros1 在先订阅后发布时 会导致订阅者无法收到订阅的消息 除非在发布者发布后重新订阅 思考 以前使用的是Ros2似乎并不关心订阅和发布的先后顺序 nbsp 似乎都可以收到消息 nbsp nbsp 这个问题后
  • C/C++中关于struct和class类的区别

    struct和class的主要的区别在于两者默认的访问权限有所不同 在不设置类中的成员属性和成员方法的权限时 xff0c struct默认的访问权限是公共权限 xff0c class默认的访问权限是私有权限 补充 xff1a 成员属性和成员
  • C++中STL容器的主要使用及含义

    1 stack栈容器的使用 假如栈中存放的是字符串 xff0c 我们做如下定义 xff1a stack lt string gt ss 设该变量名为ss 其主要用法如下 xff1a ss push a 存入栈中元素a ss top 读取栈顶
  • 电赛备赛记录第一篇(控制部分)

    2022 5 25 九校联赛备赛阶段第一天 联赛小车系统沿用去年国赛使用的树莓派驱动底板与外设 整车情况良好 xff0c 摄像头通信 连接均正常 xff0c 现已拼装完整 复产复工的初步成果为 xff1a 小车可以实现开机自启动的程序运行
  • 数据结构——栈详解

    1 栈 Stack 是一种线性存储结构 xff0c 它具有如下特点 xff1a xff08 1 xff09 栈中的数据元素遵守 先进后出 34 First In Last Out 的原则 xff0c 简称FILO结构 xff08 后进先出的
  • 双目相机标定

    一 运行环境 opencv2 windows vs 二 图像获取 分割 保存 参考博客opencv打开双目摄像头 图像切割保存 scutqq的博客 CSDN博客 双目图像分割 include amp lt opencv2 core core
  • uart1接收不定长度数据和发送:STM32 HAL库串口+DMA+IDLE空闲中断

    DMA增加 xff1a usart1 gpio 默认即可 usart1中断必须打开 在 STM32 中 USART 发送接收有三种基本方式 xff0c 轮询 中断和 DMA 1 轮询方式为堵塞模式 xff0c 使用超时管理机制 它每次接收一
  • 串口、网口等自定义通信协议的问题

    自定义通信协议的问题 一 串口1 通信分为网络通信和串口通信2 协议格式3 协议设计4 代码实现 二 网口1 TCP粘包与拆包 包的划分 出现TCP粘包的原因 粘包与拆包的几种情况 常见的粘包与拆包解决方案 2 为什么UDP没有粘包 xff