原文链接: http://blog.csdn.net/pinghegood/article/details/7841281
1.背景
最近在项目中,由于使用TD网络传输数据,数据掉包严重,软件组老大叫我来处理掉包问题。于是我就想起了在计算机网络中讲数据链路层协议时的“选择重传ARQ”协议(见《计算机网络》第四版 AndrewS.Tanenbaum的p187)来解决丢包问题。我不是一个好学生,所以具体细节忘了一些,遂找出那本书,把那一小节迅速浏览了一遍便想起了其具体工作流程。但是这个协议还不能直接应用于项目,因为发送方是搭载一颗arm芯片的传感器,arm的处理能力很弱,所以如此复杂的协议肯定是用不了。
2.具体设计
在本项目中,某个功能模块需要传感器采集5次数据,然后通过TD网络上传到PC端进行处理。每次数据作为一个大包,每个大包有128个小包。该模块需要一个大包数据收全才能使用。但是由于TD网络不稳定,所以在传输过程中,总是有小包丢失,导致这次数据就不能用。而这些传感器分布在离PC端几公里到几百公里的广阔范围内,传感器采集一次数据的时延很大(估计要1分钟左右),所以为提升系统性能,数据重传显得尤为重要。
如前所述,发送方为处理能力很弱的传感器。现成的复杂的协议不能使用,所以只能参考已有的重传方案设计新的方案。
综合以上因素,我们设计了被我称为“完成补包停等协议”的补包协议。具体过程如下图所示:
如上图所示,左边是数据重传的交换图,右边是接收方维护的两个数组:一个用来存放接收到的数据包;另一个是每个包对应的标志位,1表示还没接收,0表示已经接收。
2.1初始化
初始时,当接收方主动请求数据时,初始化相关变量:分配接收数据队列(128个空间),以及重置标志bit数组(unsigned char bit[16]),初始值为0xFF(表示所有的都还没有接收)。
如注释A所示,设置针对重传标志bit数组的定时器,延时时间根据上层给定的值确定。
2.2接收数据
当接收方接收到一个包后(如 B,C,D,E,X),它需要做以下三件事情:
(1)将该包放入数据队列的相应位置;
(2)将重传标志bit数组的相应位置0;
(3)取消上一个定时器,根据测得的时延重新对重传标志bit数组设置定时器。定时器管理使用Jacobson算法(TCP定时器管理也使用的该算法)。首先,给出一个到达连接目标端的往返时间的当前最佳估计值,用RTT表示。如果在定时器过期之前数据回来了,则测量一下这次数据传输所花的时间,用M代替。
这里是一个平滑因子,它决定了老的RTT值所占的权重。典型情况下。
如上图所示:当第2包丢失后,第3包正常到达,此时接收第3包,而对丢失的第2包不做任何处理。如果第2包延迟到达(如图中D所示),也正常接收以便减少重传包的数量。当接收完一个大包的最后一个小包或者定时器超时之后将会把重传标志bit数组发送给发送方(如图中F所示),如果此时重传标志bit数组全为0则取消相应的定时器。发送方在接收到bit数组之后,通过检测相应的位来决定重传包,如果全为0表示该大包的所有小包都正常接收了(即作为正常接收的确认消息),可以发送下一个大包的数据。其对应下发消息结构体如下所示:
- typeedof //数据重传
- {
- short type; //类型
- int etype; //子类型
- int times; //第几次采样数据(0...n需要初始化,没有采集的包就跳过并向上反馈第K包没有采集)
- char m_byteRetrancount[16] //高位...低位:1...128,全部为0表示接收完毕,可以发送下一包
- char reserve2;//预留一字节;
- }
2.3 流程图
根据以上描述,这个收包以及补包过程的流程如下所示:
3.总结
本重传方案实际上是“停等协议”和“选择重传ARQ”的混合体,在安全性方面还有很多不足之处,需要结合实际情况进一步完善。
* 学了这么多年的计算机网络,终于能用于实际项目中了,当初在学习这门课的时候还以为他就是一门扫盲课,在实际项目中永远也不会用到呢。现在想想当初的想法真幼稚,不过幸亏当初还是好好学了这门课,不然碰到这种问题就不知道从何下手了。