TCP的流量控制
一般说来,我们总是希望数据传输得更快一些。但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。所谓流量控制( flow control)就是让发送方的发送速率不要太快,要让接收方来得及接收。
设A向B发送数据。在连接建立时,B告诉了A:“我的接收窗口rwnd=400”(这里rwnd表示 receiver window)。因此,发送方的发送窗口不能超过接收方给出的接收窗口的数值。TCP的窗口单位是字节,不是报文段。
当B发出的rwnd=0时,相当于B告诉A“你不要再发数据啦,我收不下啦!”,A就会不继续给B发送数据了。
现在我们考虑一种情况。如果当B向A发送了零窗口的报文段后不久,B的接收缓存又有了一些存储空间。于是B向A发送了rwnd=400的报文段。然而这个报文段在传送过程中丢失了。A一直等待收到B发送的非零窗口的通知,而B也一直等待A发送的数据。如果没有其他措施,这种互相等待的死锁局面将一直延续下去。
为了解决这个问题,TCP为每一个连接设有一个持续计时器( persistence timer)。只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带1字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。如果窗口仍然是零,那么收到这个报文段的一方就重新设置持续计时器。如果窗口不是零,那么死锁的僵局就可以打破了。
TCP的拥塞控制
在计算机网络中的链路容量(即带宽)、交换结点中的缓存和处理机等,都是网络的资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫做拥塞( congestion)。可以把出现网络拥塞的条件写成如下的关系式:
网络拥塞往往是由许多因素引起的。例如,当某个结点缓存的容量太小时,到达该结点的分组因无存储空间暂存而不得不被丢弃。现在设想将该结点缓存的容量扩展到非常大。
于是凡到达该结点的分组均可在结点的缓存队列中排队,不受任何限制。由于输出链路的容量和处理机的速度并未提高,因此在这队列中的绝大多数分组的排队等待时间将会大大增加,结果上层软件只好把它们进行重传(因为早就超时了)。由此可见,简单地扩大缓存的存储空间同样会造成网络资源的严重浪费,因而解决不了网络拥塞的问题。
又如,处理机处理的速率太慢可能引起网络的拥塞。简单地将处理机的速率提高,可能会使上述情况缓解一些,但往往又会将瓶颈转移到其他地方。问题的实质往往是整个系统的各个部分不匹配。只有所有的部分都平衡了,问题才会得到解决。
拥塞控制与流量控制的关系密切,它们之间也存在着一些差别。所谓拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。但TCP连接的端点只要迟迟不能收到对方的确认信息,就猜想在当前网络中的某处很可能发生了拥塞,但这时却无法知道拥塞到底发生在网络的何处,也无法知道发生拥塞的具体原因(是访问某个服务器的通信量过大?还是在某个地区出现自然灾害?)
由于计算机网络是一个很复杂的系统,因此可以从控制理论的角度来看拥塞控制这个问题。这样,从大的方面看,可以分为开环控制和闭环控制两种方法。
开环控制方法就是在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞。但一旦整个系统运行起来,就不再中途进行改正了。
闭环控制是基于反馈环路的概念。属于闭环控制的有以下几种措施:
(1)监测网络系统以便检测到拥塞在何时、何处发生
(2)把拥塞发生的信息传送到可。取行动的地方。
(3)调整网络系统的运行以解决出现的问题。
此外,过于频繁地采取行动以缓和网络的拥塞,会使系统产生不稳定的振荡。但过于迟缓地采取行动又不具有任何实用价值。因此,要采用某种折中的方法。但选择正确的时间常数是相当困难的。
几种拥塞控制方法
1999年公布的因特网建议标准RFC2581定义了进行拥塞控制的四种算法,即慢开始(slow-start)、拥塞避免( ongestion avoidance)、快重传( Fast retransmit)和快恢复 (fast recovery)。
为了集中精力讨论拥塞控制,我们假定:
(1)数据是单方向传送,而另一个方向只传送确认。
(2)接收方总是有足够大的缓存空间,因而发送窗口的大小由网络的拥塞程度来决定。
慢开始和拥塞避免
发送方维持一个叫做拥塞窗口cwnd( congestion window的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口。以后我们就知道,如果再考虑到接收方的接收能力,那么发送窗口还可能小于拥塞窗口。
发送方控制拥塞窗口的原则是:只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去。但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。
简单来说,慢开始就是先把cwnd设置为一个MSS的值(最大报文段),也就是先发送一个报文,如果收到了确认后,把cwnd的值*2,也就是可以发送两个报文。cwnd的值是以指数形式增长的。
慢开始的“慢”并不是指cwnd的增长速率慢,而是指在TCP开始发送报文段时先设置cwnd=1,使得发送方在开始时只发送一个报文段(目的是试探一下网络的拥塞情况),然后再逐渐增大cwnd。这当然比按照大的cwnd一下子把许多报文段突然注入到网络中要“慢得多”。这对防止网络出现拥塞是一个非常有力的措施。
而拥塞避免就是先把cwnd设置为一个MSS的值(最大报文段),也就是先发送一个报文,如果收到了确认后,把cwnd的值加一个MSS的值,也就是线性增长,每次收到确认后,可以发送1,2,3,4,5,6...个报文。
慢开始和拥塞避免一般是一起使用的。
这里还要介绍一个变量叫慢开始门限(ssthresh)。
慢开始门限 ssthresh的用法如下:
- 当cwnd < ssthresh时,使用上述的慢开始算法。
- 当 cwnd > ssthresh时,停止使用慢开始算法而改用拥塞避免算法
- 当 cwnd = ssthresh时,既可使用慢开始算法,也可使用拥塞避免算法
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络岀现拥塞(其根据就是没有按时收到确认),就要把慢开始门限 ssthresh设置为出现拥塞时的发送方窗口值的一半(但不能小于2),然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。
也就是说,一开始使用慢开始发送一个报文,收到确认后翻倍发送,当翻倍到ssthresh时,不翻倍增长了,而是加一,加到发生网络拥塞时,也就是开始收不到确认时,把当前发送的报文的所有MSS加到一起除以二,赋给新的ssthresh值,然后把cwnd设为一个MSS的值,也就是重新开始,使用慢开始,只发送一个报文,重复这个过程,直至数据发送完毕。
快重传和快恢复
如果发送方设置的超时计时器时限已到但还没有收到确认,那么很可能是网络出现了拥塞,致使报文段在网络中的某处被丢弃。在这种情况下,TCP马上把拥塞窗口cwnd减小到1,并执行慢开始算法,同时把慢开始门限值 ssthresh减半这是不使用快重传的情况。
再看使用快重传的情况。快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等待自己发送数据时才进行捎带确认。在下图所示的例子中,接收方收到了M1和M2后都分别发出了确认。现假定接收方没有收到M3但接着收到了M4.显然,接收方不能确认M4,因为M4是收到的失序报文段(按照顺序的M3还没有收到)。根据可靠传输原理,接收方可以什么都不做,也可以在适当时机发送一次对M2的确认。但按照快重传算法的规定,接收方应及时发送对M2的重复确认,这样做可以让发送方及早知道报文段M3没有到达接收方。发送方接着发送M和M6接收方收到后,也还要再次发出对M2的重复确认。这样,发送方共收到了接收方的四个对M2的确认,其中后三个都是重复确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段M3,而不必继续等待为M3设置的重传计时器到期。由于发送方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络的吞吐量提高约20%。
与快重传配合使用的还有快恢复算法,其过程有以下两个要点:
(1)当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把慢开始门限ssthresh减半。这是为了预防网络发生拥塞。接下去不执行慢开始算法。
(2)由于发送方现在认为网络很可能没有发生拥塞(如果网络发生了严重的拥塞,就不会一连有好几个报文段连续到达接收方,就不会导致接收方连续发送重复确认),因此与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口cwnd现在不设置为1),而是把cwnd值设置为慢开始门限 ssthresh减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。
在讨论拥塞控制的开始我们就假定了接收方总是有足够大的缓存空间,因而发送窗口的大小由网络的拥塞程度来决定。但实际上接收方的缓存空间总是有限的。接收方根据自己的接收能力设定了接收窗口rwnd,并把这个窗口值写入TCP首部中的窗口字段,传送给发送方。
因此,接收窗口又称为通知窗口( advertised window)。因此,从接收方对发送方的流量控制的角度考虑,发送方的发送窗口一定不能超过对方给出的接收窗口值rwnd。
如果把拥塞控制和接收方对发送方的流量控制一起考虑,那么很显然发送方的窗口的上限值应当取为接收方窗口rwnd和拥塞窗口cwnd这两个变量中较小的个,也就是说:
- 当rwnd<cwnd时,是接收方的接收能力限制发送方窗口的最大值。
- 反之,当rwnd>cwnd时,则是网络的拥塞限制发送方窗口的最大值M。
也就是说,rwnd和cwnd中较小的一个控制发送方发送数据的速率。