(二十七)运输层--TCP的拥塞控制方法

TCP的拥塞控制方法

TCP进行拥塞控制的算法有四种,即慢开始、拥塞避免、快重传、快恢复。为了专注讨论拥塞控制,假定:
(1)数据是单方向传送的,对方只传送确认报文
(2)接收方总是有足够大的缓存空间,因而发送窗口的大小由网络的拥塞程度来决定

下面讨论的拥塞控制也叫做基于窗口的拥塞控制。为此,发送方维持一个叫做拥塞窗口 cwnd 的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口等于拥塞窗口。

发送方控制拥塞窗口的原则是:只要网络没有出现拥塞。拥塞窗口就可以再增大一些,以便把更多的分组发送出去,这样就可以提高网络的利用率。但只要网络出现拥塞或有可能出现拥塞,就必须把拥塞窗口减小一些,以减少注入到网络中的分组数,以便缓解网络出现的拥塞。

发送方如何知道网络发生了拥塞呢?我们知道,当网络发生拥塞时,路由器就要丢弃分组。因此只要发送方没有按时收到应当到达的确认报文,就可以猜想网络出现了拥塞。下面讨论拥塞窗口的变化。

慢开始

当主机开始发送数据时,由于并不清楚网络的负荷情况,所以如果立即把大量数据字节注入到网络,就有可能引起网络拥塞。经验证明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口(增大拥塞窗口数值)。

旧的规定是这样的:在刚刚开始发送报文段时,先把初始拥塞窗口 cwnd 设置为1至2个发送方的最大报文段(SMSS)数值,但新的 RFC 5681 把初始拥塞窗口 cwnd 设置为不超过2至4个SMSS的数值,具体如下:

  • 若 SMSS > 2190字节,则设置初始拥塞窗口 cwnd = 2 x SMSS字节,且不得超过2个报文段

  • 若 1095字节 < SMSS ≤ 2190字节,则设置拥塞窗口 cwnd = 3 x SMSS字节,且不得超过3个报文段

  • 若 SMSS ≤ 1095字节,则设置初始拥塞窗口 cwnd = 4 x SMSS字节,且不得超过4个报文段

慢开始规定,在每收到一个对新的报文段的确认后,可以把拥塞窗口增加最多一个 SMSS 的数值。更具体些,就是:

拥塞窗口 cwnd 每次的增加量 = min(N, SMSS)

N是原先未被确认的,现在刚收到的确认报文段所确认的字节数。

下面举个例子说明慢开始算法的原理。虽然TCP是用字节数作为窗口大小的单位。但为了叙述方便,以下是用报文段的个数作为窗口大小的单位,这样可以使用较小的数字来阐明拥塞控制的原理。

在一开始发送方先设置 cwnd = 1,发送第一个报文段M1,接收方收到后确认M1。发送方收到对M1的确认后,把 cwnd 从1增大到2,接着发送M2和M3两个报文段。接收方收到后发回对M2和M3的确认。发送方每收到一个对新报文段的确认(重传的不算在内),就使发送方的拥塞窗口加1。因此,发送方在收到两个确认后,cwnd 就从2增大到4,并可发送M4~M7共4个报文段。可见使用慢开始算法后,每经过一个传输轮次,拥塞窗口就加倍。

上面使用了一个名词——传输轮次。从上图可以看出,一个传输轮次所经历的时间就是往返时间RTT。使用传输轮次是更加强调:把拥塞窗口 cwnd 所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。例如,拥塞窗口 cwnd 的大小是4个报文段,那么这时的往返时间RTT就是发送方连续发送4个报文段,并收到这4个报文段的确认,总共经历的时间。

慢开始的慢并不是指 cwnd 的增长速率慢,而是指TCP开始发送报文段时先设置 cwnd = 1,使得发送方在开始时只发送一个报文段,然后再逐渐增大 cwnd,这当然比设置大的 cwnd 值一下子把许多报文段注入到网络中要“慢得多”。这对防止网络出现拥塞是一个非常好的方法。

在TCP的实际运行中,发送方只要收到一个对新报文段的确认,其拥塞窗口 cwnd 就立即加1,并可以立即发送新的报文段,而不需要等这个轮次中所有的确认都收到后,再发送新的报文段。

为了防止拥塞窗口 cwnd 增长过大引起网络拥塞,还需要设置一个 慢开始门限 状态变量。慢开始门限 ssthresh 的用法如下:

  • 当 cwnd < ssthresh 时,使用上述的慢开始算法

  • 当 cwnd > ssthresh 时,使用下述的拥塞避免算法

  • 当 cwnd = ssthresh 时,即可使用慢开始算法,也可使用拥塞避免算法

拥塞避免

拥塞避免的思路是让拥塞窗口 cwnd 缓慢的增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加1,而不是像慢开始阶段那样加倍增长。即在拥塞避免阶段,拥塞窗口 cwnd 按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢很多。

下图用具体例子说明了在拥塞控制的过程中,TCP的拥塞窗口 cwnd 是怎样变化的。现假定TCP的发送窗口等于拥塞窗口。

当TCP连接进行初始化时,把拥塞窗口 cwnd 置为1。在本例中,慢开始门限的初始值设置为16个报文段,即 ssthresh = 16。在执行慢开始算法时,发送方每收到一个对新报文段的确认ACK,就把拥塞窗口值加1,然后开始下一轮的传输,拥塞窗口 cwnd 随着传输轮次按指数规律增长。当拥塞窗口 cwnd 增长到慢开始门限值 ssthresh时,按线性规律增长。但拥塞避免并非完全能够避免拥塞,只是说控制为按线性规律增长,使网络比较不容易出现拥塞。

当拥塞窗口 cwnd = 24 时,网络出现了超时,发送方判断为网络拥塞。于是调整门限值 ssthresh = cwnd / 2 = 12,同时设置拥塞窗口 cwnd = 1,重新进入慢开始阶段。按照慢开始算法,发送方每收到一个对新报文段的确认ACK,就把拥塞窗口值加1。当拥塞窗口 cwnd = ssthresh = 12时,改为执行拥塞避免算法,拥塞窗口按线性规律增大。

快重传

如上图,当拥塞窗口 cwnd = 16时,出现了一个新的情况,就是发送方一连收到3个对同一个报文段的重复确认。有时个别报文段会在网络中丢失,但实际上网络并未发生拥塞。如果发送方迟迟收不到确认,就会产生超时,就会误认为网络发生了拥塞。这就导致发送方错误的启动慢开始,把拥塞窗口 cwnd 又设置为1,因而降低了传输效率。

采用快重传算法可以让发送方尽早知道发生了个别报文段的丢失。快重传算法首先要求接收方不要等待自己发送数据时才进行稍待确认,而是要立即发送确认,即使收到了失序的报文段,也要立即发出对已收到的报文段的重复确认。如下图所示,接收方收到了M1和M2后都分别及时发出了确认。现假定接收方没有收到M3,但却收到了M4。本来接收方可以什么也不做,但按照快重传算法,接收方必须立即发送对M2的重复确认,以便让发送方及早知道接收方没有收到报文段M3。发送方共收到了接收方的4个对M2的确认,其中后3个都是重复确认。快重传算法规定,发送方只要一连收到3个重复确认,就知道接收方确实没有收到报文段M3,应当立即进行重传。使用快重传可以使整个网络的吞吐量提高约20%。

快恢复

因此,上上图中的点4,发送方知道现在只是丢失了个别的报文段。于是不启动慢开始,而是执行快恢复算法。这时,发送方调整门限值 ssthresh = cwnd / 2 = 8,同时设置拥塞窗口 cwnd = ssthresh = 8(节点5),并开始执行拥塞避免算法。

有的快恢复实现是把快恢复开始时的拥塞窗口 cwnd 值在增大一些(增大3个报文段的长度),即等于新的 ssthresh + 3 x MSS。这样做的理由是:既然发送方收到3个重复的确认,就表明有3个分组已经离开了网络。这3个分组不再消耗网络的资源而是停留在接收方的缓存中(因为发出了3个重复的确认)。可见现在网络中并不是堆积了分组而是减少了3个分组,因此可以适当把拥塞窗口扩大一些。

根据以上所述,TCP的拥塞控制可以归纳为下面这个流程图:

本文的讨论假定了接收方总是有足够大的缓存空间,因而发送窗口的大小由网络的拥塞程度来决定。但实际上接收方的缓存空间总是有限的。接收方根据自己的接收能力设定了接收方窗口 rwnd,并把这个窗口值写入TCP首部中的窗口字段,传送给发送方。因此,接收方窗口又称为通知窗口。从接收方对发送方的流量控制的角度考虑,发送方的发送窗口一定不能超过对方给出的接收方窗口值。

如果把拥塞控制和接收方对发送方的流量控制一起考虑,那么很显然,发送方的窗口的上限值应当取为接收方窗口 rwnd 和拥塞窗口 cwnd 这两个变量中较小的一个。(较小的那个值控制了发送方发送数据的速率)

posted @ 2021-07-17 14:03  明说  阅读(681)  评论(0编辑  收藏  举报