TCP/IP的确认号,序列号和超时重传的学习笔记

一:确认应答和序列号

在tcp中,发送端的数据到达主机时,接收端会返回一个已收到的通知。这个消息叫做确认应答(ACK)。

当发送端发送数据后,会等待对端的确认应答。如果有确认应答,说明数据已经成功到达。反之,则数据丢失的可能性很大。

发送端一定时间内没有等到确认应答,发送端就认为数据已经丢失了,就可以重发数据。因此,即使产生了丢包,也能保证数据到达对端。实现可靠传输。

想一下:为什么发送端一定时间内没有收到确认应答呢?有哪些原因呢?

这里有几个对象:

1、发送端,发送的数据

2、对端,回应的ACK数据

3、中间的网络

第一种 发送端:发送端的数据根本没有到达对端,发送的数据在途中就已经丢失了。

第二种 对端:可能数据对方已经收到了,只是回应ACK的数据时,途中丢失了。这种情况会导致发送端没有收到对端的确认应答。

第三种:网络:由于网络拥堵,确认应答ACK延迟到达了。或者发送端的数据延迟到达对端了。这种情况也可能导致重发数据包。

上面这些情况都有可能导致发送端没有收到对端的ACK应答。

上面说了, 如果需要发送端重发数据,那需要重发哪部分数据,发送端怎么知道重发哪部分数据?

这个就是序列号功能了。

什么是序列号:

序列号是按照顺序给发送数据的每一个字节都编号。

接收端接收数据TCP首部中的序列号和数据长度,将自己下一步接收的序号作为确认应答发送回去。

这样,通过序列号和确认应答号,就可以实现TCP的可靠传输。

上面谈到了重发数据情况,那什么时候重发数据呢? 这个时间怎么计算?
也就是说,这个重发的时间怎么确定?什么时候开始计时的?

二:重发和重发超时时间

重传定时器

要实现超时重发,就是在发送完一组数据时,就立即给这组数据设置一个超时定时器。如果定时器到期之前收到了对端的确认号,就撤销重传超时定时器。

超时时间怎么设置:

  • 如果设置的长一点,重发数据就变慢了,效率就变差了;
  • 如果设置的短一点,可能会导致数据还没丢就重发了。这样的话,重发数据就变快了,自然会增加网络负担,导致网络拥塞,一拥塞,就会导致更多的超时,超时又导致更多的重发。

所以这个时间的设置就变得很重要了。

先看看发送数据的几个步骤:

  1. 发送端发送数据,并启动重传定时器
  2. 等待对端的应答ACK号
  3. 重传定时器到期

这里有几个时间的概念:

  1. RTT(Round Trip Time):发送一个数据包到收到对端的ACK所花费的时间
  2. RTO(Retransmission TimeOut): 发送数据包,启动重传定时器,重传定时器到期所花费的时间,称为RTO

网络又是复杂的,由各种主机,路由器,网络等组成。所以这个重传时间RTO只能动态来计算了。
经过一些计算机专家的研究,它是根据RTT来动态计算的。

重传时间算法

第一种经典算法:RFC793

  1. 首先计算一个平滑的RTT称为SRTT, alpha是一个平滑因子,取值为0.8或者0.9
SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)
  1. 基于SRTT,计算出对应的RTO
RTO = min[UBOUND, max[LBOUND, (BETA*SRTT)]

其中UBOUND是最大值,一般情况下为120s,LBOUND是最小重传值,一般情况下为1s,Beta也是一个因子,建议取值为1.3~2.0.
这个算法来自 RFC793

但是这个算法在目标Linux中没有使用,原因是存在不足。有文章指出:从公式可以看到在经典的RTO计算方法中会有一个很大的问题,就是当RTT对RTO的影响太小了,也就是说经典的RTO计算方法在RTT变化比较大的网络中,会表现的非常不好的。

第二种算法:Jacobaon/Karels 算法

1988年,Van Jacobson和Karels在Congestion Avoidance and Control这篇论文中提出一种新的算法RFC6298,这里对于rtt的采样,多添加了一个因素,那就是均差(mean deviation),而这里并不是传统意义上的均差,使用的平均数其实就是我们在经典方法中的srtt。

第一次RTO计算方法, 假设RTT = R

1. SRTT = R

2. RTTVAR = R/2

3. RTO = SRTT + max(G, K*RTTVAR) , K = 4

后续的RTO计算,假设当前的RTT为R'

RTTVAR = (1 - beta)*RTTVAR + beta*|SRTT - R'|
//计算平滑RTT和真实RTT的差距,切记这个地方的SRTT是上一次的SRTT
SRTT = (1 - alpha)*SRTT + alpha*R'
//计算平滑RTT, 及是SRTT
RTO = SRTT + max(G, K*RTTVAR)
//计算 RTO

alpha = 1/8  beta = 1/4,值得指出的是这个算法在目前的Linux协议栈中应用

第二种算法到底有啥好处,可以去查看相关文章看看

参考

posted @ 2017-12-02 00:17  九卷  阅读(1182)  评论(0编辑  收藏  举报