TCP的计数器

     

      为了能够顺利的进行TCP的操作,大多数的TCP实现至少要使用4个计时器,见下图。

重传计数器

为了重传丢失的报文段,TCP应用了一个重传计时器(在整个连接期间)来处理重传超时(RTO),也就是对报文段的确认的等待时间。我们可以以为重传计时器定义一下规则:

  • 当TCP发送了位于发送队列最前端的报文段后,就启动这个计时器。
  • 当这个计时器超时后,TCP重传位于发送队列最前端的报文段,并重启这个计时器。
  • 当一个(或多个)报文段被累计确认后,这个(或这些)报文段被消除出队列。
  • 如果队列为空,TCP停止这个计时器,否则TCP重启计时器

往返时间(RTT)

     要计算重传的超时期限(RTO),我们首先要计算往返时间(round trip time,RTT),但是计算TCP中的RTT是个复杂的过程,我们将通过一些例子逐步了解它。

测量RTT

         我们需要找出从发送出去一个报文段到对它的确认需要多少时间。这就是测量RTT。我们应当记住,报文段和他的确认之间并非一对一的关系,好几个报文段有可能会被一起确认。一个报文段的测量RTT是指这个报文段到达终点并被确认需要的时间,虽然这个确认可能还包括对其他报文段的确认。请注意,在TCP中,任何时刻只能有一个正在运行的RTT测量。也就是说,如果RTT测量开始了,那么在这次的RTT测量结束之前,不能再开始其他测量。我们使用记法RTT(m)表示测量RTT。

平滑RTT

      测量RTT很可能每次往返都有变化。在目前的因特网中,RTT测量值的起伏非常大,以至于单词测量值无法被用于重传超时的目的。绝大多数实现使用的是一种平滑RTT,记为RTT(s),它是对RTT(m)和前一个RTT(s)的加权平均,如下表示:

α的取值与实现有关,但通常为1/8.换言之,新的RTT(s)是由7/8的旧RTT(s)和1/8的当前RTT(m)相加而成。

RTT的偏差

        大多数的实现不仅使用了RTT(s),还要计算RTT的偏差,称为RTT(d).它是根据RTT(s)和RTT(m)并使用下面公式计算得到的:

β的取值与实现有关,但通常为1/4.

 

重传超时(RTO)

       RTO的数值基于平滑的往返时间和它的偏差值。绝大多数实现使用下面的公式计算RTO:

换言之 ,就是用但钱的RTT(s)值,加上当前的RTT(d)值(通常是个较小的数)的四倍。

 

 

下图所示为一个连接的一部分。图中画出了连接建立阶段和部分数据传送阶段。

1、当SYN报文段发送后,没有RTT(m)、RTT(s)或RTT(d)的值。RTO值设为6.0秒,下面给出此时这些变量的值为:

 

2、当SYN+ACK报文段到达时,测量出RTT(m)等于1.5秒,下面给出的这些变量的值:

RTT(m)=1.5

RTT(s)=1.5

RTT(d)=1.5/2-0.75

RTO=1.5+4*0.75=4.5

 

3、当第一个报文段被发送后,新的RTT测量就开始了,请注意,在发送发发送ACk报文段时不能开启下一次RTT的测量过程,因为ACK报文段不消耗序号,也没有超时。在发送第二个数据报文段时也没有测量RTT,因为已经有一个RTT测量正在进行之中。最后一个ACK报文段的到达用来计算RTT(m)的下一个数值。虽然最后一个ACK报文段确认了两个数据报文段(累积的),但它的到达完成的是对第一个数据报文段的RTT(m)的计算。现在这些变量的值如下:

RTT(m)=2.5

RTT(s) =7/8 X 1.5 + 1/8 X 2.5=1.625

RTT(d) = 3/4 X(0.75) x | 1.625-2.5| = 0.78

RTO=1.625+4X0.78=4.74

 

Karn算法

       假定有一个报文段在重传计时器超时前未被确认,因而重传。当发送TCP收到对这个报文段的确认时,它无法知道这个确认是对原来报文段的确认,还是对重传报文段的确认,因为新的RTT值要根据报文段发送的时间来计算。但是如果原始的报文段丢失了而确认是对重传的报文段确认,则当前的RTT的计算就必须从重传的报文段发送的时间算起。这种模糊性被Karn解决了。Karn的算法很简单。在计算新的RTT时,不需要考虑重传报文段的往返时间。除非你发送了一个报文段并且在没有被重传的条件下收到了确认,否则不要更新RTT的值。TCP在计算新的RTO时不考虑重传报文段的RTT。

 

指数退避

       如果发生了重传,那么RTO的指数是什么?大多数的TCP使用指数退避的策略。每一次重传,RTO的数值就加倍。因此,如果报文段重传一次,这个值就是两倍的RTO。如果它被重传了两次,这个值就编程了四倍的RTO一次类推。

       下图所示为前面例子的延续,这次出现了重传,因而用到了Karn算法。

       

       图中的第一个报文段发送出去,但丢失了。经过4.74秒后,RTO计时器到期。这个报文段被重传,而计时器被设置为9.48秒,原来的RTO值的两倍。这次在计时器超时之前收到了ACK。我们继续等待,直至我们发送一个新的报文段,并收到了对它的确认,然后才能重新计算RTO(Karn算法)。

 

 

持续计时器

       为了处理零窗口值的通道,TCP需要另一个计时器。如果接收TCP宣布窗口为零,那么发送TCP就会停止发送报文段,直至收到TCP发送来一个宣布窗口大小非零的确认。但是这个ACK报文段可能丢失。应当记住,在TCP中的确认报文段既不需要确认,也不需要重传。如果确认报文段丢失了,接收TCP仍然认为这个确认已经完成了任务,并等待着发送TCP下面的报文段。对于仅包含有一个确认的报文段是没有重传计时器的。发送TCP由于没有收到确认,就等待对方发送一个确认来通知窗口的大小。这两个TCP都在永远等待着对方(死锁)。

         为了纠正这个死锁问题,TCP为每个连接使用一个持续计时器(persistence timer)。当发送TCP接收窗口值为零的确认时,就启动一个持续计时器。当持续计时器超时后,发送一个TCP特殊的报文段,称为探测报文段。这个报文段只有1个字节的新数据。它有序号,但它的需要永远不需要确认,甚至在计算剩余数据的序号时,这个序号也被忽略。探测报文段促使接收TCP重传一个确认。

        持续计时器的时间长度被设置为重传时间的值。但是若没有收到从接收方发送来的响应,则需要发送另一个探测报文段,并将其持续计时器的值加倍,且该计时器复位。发送方继续发送探测报文段,不断地将持续计时器的值加倍和复位,直到这个值达到一个门限(通常是60秒)为止。在这以后,发送端每个60秒就发送一个探测报文段,直到窗口重新打开。

保活计时器

       某些实现中要使用报货计时器(keepalive timer)来防止两个TCP之间的连接长时间空闲。假定一个客户端打开了到服务器的一条连接,传送过一些数据,然后就变的静默了。也许是因为这个客户处了什么故障。在这种情况下,这个连接将永远处于打开状态。

       为了解决这个问题,绝大多数的实现都是给服务器设置了一个保活计时器。每当服务器收到客户的信息,就把该计时器复位。超时通常设置为2个小时。若服务器过了两个小时还没有收到客户端的任何消息,它就发送一个探测报文段。若联系发送了10个探测报文段(每隔75秒一个)没有收到响应,它就假定客户出了故障,并终止这个连接。

TIME-WAIT计时器

        TIME-WAIT(2msl)计时器是在连接终止期间使用的。参考TCP状态转换图

猜你喜欢

转载自woodding2008.iteye.com/blog/2341359