众所周知,
TCP
是可靠数据传输协议,其是基于不可靠的
IP
层传输之上,建立自身的数据传输控制协议,由控制算法实现了可靠的数据传输。参照
TCP
协议以及若干版本的
TCP
堆栈实现过程,我们可以实现任意基于
IP
的可靠数据传输堆栈。实现可靠以及高效的可靠数据传输,主要涉及到逻辑端口、滑动窗口、慢启动、
RTT
、快速重传、
delay ack
以及乱序丢包处理。
一、
逻辑端口
数据传输端口是传输建立对应关系的键值,其是网络数据传输堆栈的逻辑数据,而并不是物理存在的单元。为了提高由端口查找对应逻辑数据控制块的效率,一般实现方法是建立二叉树结构保存端口和逻辑数据控制块,同时为了接近二叉树最高的查找效率,端口分配一般是采用递增回绕的分配方式。
二、
滑动窗口
对于发送方在发送
IP
数据包的过程中,如何使传输既能高效,同时又不会因为发送过快导致接收方处理慢而使接收缓冲区溢出丢失后面的数据,
tcp
堆栈采用滑动窗口的机制。窗口大小由接收方通告发送方,发送方发送数据后右移可用窗口左边框减少滑动窗口大小,接收方收到数据包发送确认,发送方收到确认后,首先提取窗口大小并更新,然后右移可用窗口右边框增大滑动窗口大小。当接收方收到发送方发送的数据,会在确认的同时把数据放入接收缓冲区,当缓冲区可用空间大小小于窗口大小时,会更新窗口大小。当上层从接收缓冲区取出数据,缓冲区可用空间增大时,也会更新窗口大小。
三、
慢启动
在实际的可靠网络传输中,并不是数据传输双方建立可靠连接后,发送方就直接发送接收方通告窗口大小的数据,这是为了避免在广域网的多级路由环境下路由缓存限制造成的丢包问题。发送方增加一个窗口,称为拥塞窗口,发送方发送数据时窗口大小会取通告窗口大小和拥塞窗口大小的最小值。当连接建立时,拥塞窗口大小初始化为一个报文段的大小,在传输过程中,每收到一个确认数据包,拥塞窗口大小会增加一个报文段大小,需要说明的是有些堆栈是指数级增加。
四、
超时时间
rtt
发送端向接收端发送数据包之后,会把未确认的数据包放入未确认队列,等待接收端的确认,如果数据包在链路中被丢失,发送端在收不到确认的情况下,需要进行重发。进行重发的条件为一个阀值时间内没有收到确认,则重发。这个阀值时间我们成为
RTT
。发送一个数据包时,取当前时钟的值,当该数据包的确认返回时,再取时钟值,两次时钟偏差为本次的
RTT
值
,
记为
M
。传输模型为了处理真实环境变化起伏较大的情况,引入均值和方差来计算
RTT
。
Err = M �C A
A <- A + gErr
D <- D + h(| Err| - D)
RTT = A + 4D
其中
A
为均值
D
为方差
Jacob
模型中
g = 1/8 h = 1/4
五、
快速重传
在实际传输环境中,发送方向接收方连续发送了
n
(
n<
滑动窗口大小)个
IP
包,由于网络原因,接收方有可能收到
n �C 1
个包,其中第
j
个包没有收到,当接收方收到第
j+1, j + 2 , ..n
个包后,立即返回确认(
ack
),
ackno
为第
j �C 1
个包的确认号。
发送方收到重复
ackno
的确认后,记录该确认号的重复次数,当达到阀值后,则进入快速重传流程。由于重新排序处理只可能产生
1-2
个重复的
ACK
,所以这个阀值设定为
3
。快速重传的流程为:
1、
重传第
j
个数据包,把拥塞窗口设置为当前拥塞窗口的一半加
3
个报文段大小。
2、
后面每收到一个重复的确认,则把拥塞窗口大小加一个报文段大小,并发送一个数据包。
3、
当收到正常的确认,即
第
J
或
j +
包的确认,再把拥塞窗口大小设置为之前的一半,进入正常的传输流程。
快速重传恢复算法是处理正常快速的网络环境中,网络设备偶然发生的丢包乱序现象,因为网络环境并没有恶化,所以没有必要走慢启动流程,而只是把发送速度减半,进行快速恢复。
六、
Delay ack
在高速网络中,发送方发送数据包,接收方发送
ack
进行确认,但是如果对每个数据包都进行确认,即存在效率问题,又浪费了网络带宽。在一般
TCP
实现堆栈中,是使用
200
毫秒定时器进行时延确认。具体流程为:
1、
接收方收到数据包,取出
seqno,
更新
ackno.
2、
确认定时器溢出,根据
ackno
发送
ack
包。
但是这种方法会造成发送方可用滑动窗口小于一个报文段时,接收方没有即时确认更新窗口而造成效率浪费。所以在改进实现中,可以设立一个标识,该标识为紧急确认标识,当接收方收到该标识的报文,则立即确认。
七、
丢包以及乱序处理
可靠传输的双端数据在经过中间网络设备时,由于设备缓存限制、路由路径的不一致或其他原因,很有可能发生乱序或丢包情况。如果发生乱序以及偶然丢包(符合快速重传条件的丢包),则由处理逻辑发送端进行快速重传。而有些情况是发送端发送了
n
个包,由于中间一台路由器缓存达到上限,从第
j (j < n)
个包开始所有的包都被丢失,
接收端只收到了前
j �C 1
个包,并确认前
j �C 1
个包,发送端迟迟收不到后继包的确认,等待
RTT
超时之后,进入超时重传流程,发送端把慢启动窗口大小置为一个报文段大小,并且发送第
j
个报文段。