在前面的描述中,无论是TCP流量控制还是差错控制当中,都会假设发送端一开始就向接收端发送多个报文段直到耗尽自己的信用量。如果发送端和接收端处于同一个局域网中,这种方法是可以的。但如果在两者之间存在着多个路由器或是较慢速率的链路时,就可能会出现一些问题。因为路由器中的缓存区通常是由很多TCP连接和非TCP数据流共享的,因而路由器很可能会出现因为缓存各个TCP连接的报文段而耗尽存储器空间的情况。这种情况称为拥塞。发生拥塞状况后,路由器只是简单地丢弃新收到的报文段,而不会通知发送端。当然,如果重传定时器超时,发送端也可以推断出路由沿途出现了拥塞。如果不采取任何策略的话,发送的数据越多,被丢弃的数据越多,重传的数据也越多,只会导致拥塞进一步恶化,严重降低TCP连接的吞吐量。
TCP从两方面入手,对拥塞进行控制,一方面是重传计时器管理,另一方面是窗口管理。重传计时器管理包括简单平均算法、Jacobson算法、Karn算法等。窗口管理包括慢启动算法、拥塞避免算法、快速恢复算法等。
1.重传计时器管理
在TCP差错控制中,重传计时器是最常被用到的,无论是哪种差错,重传计时器都起着非常重要的作用。因而,如何设置重传计时器的值在很大程度上直接影响着TCP的性能。
如果重传计时器的值太小,就会造成经常性的超时,从而导致不必要的重传,浪费网络的容量,加剧网络的拥塞;如果值太大,就会对报文段丢失的反应非常迟缓,造成很大的延时。从最为直观的角度而言,这个值应该比发送报文段和接收确认的一个往返的环路时间(RTT)要大一些,但也不要大太多,最好能处于一个数量级。但如果想通过这样的想法来为定时器设置一个固定值是很困难的,因为不仅计算机相互之间的RTT不一样,就是相同的两台计算机之间,每次数据和确认往返的RTT也可能差别很大。为了解决这个问题,TCP只能不断地测试连接的RTT,动态更新重传计时器的值。因此对于重传计时器值的设定,有多种多样的算法,例如,简单平均算法、Jacobson算法、Karn算法等。其实哪一种算法都很难做到完美。
简单平均算法就是对报文段的往返时间RTT进行观察,简单地取其平均值。
Jacobson算法是估计RTT的变化,利用RTT方差估值决定重传计时器的值RTO。
Jacobson算法只用于处理正常的情况,但是当发生重传后,如果收到一个确认,这时候就不用这个算法来调整RTO值了。因为无法判断这个确认是针对第一次传输,还是后来的重传。在这种情况下,采用Karn算法来调整RTO的值。Karn算法如下。
1)对于发生重传的报文段,在收到确认后,不更新RTT。
2)重传时,RTO是倍增的,直到达到最大值的限制。如果重传超过一定的次数,就断开TCP连接。
3)在重传并收到确认后,如果下一次的报文段没有发生重传(即一次性收到确认),则又恢复Jacobson算法。
2.慢启动算法
TCP需要支持一种被称为“慢启动”的算法。当TCP刚建立连接或从拥塞状态恢复时,如果仍按正常情况把信用量内的数据统统发送出去,在发送方因超时意识到流量过大之前,互联网可能已经又拥塞了。
慢启动算法是让发送方从较小的窗口开始发送,逐渐逼近最大窗口值——信用量。该算法通过观察新分组进入网络的速率是否与另一端返回确认的速率相同而进行工作。
慢启动为发送方的TCP增加了另一个窗口:拥塞窗口。当与另一个网络的主机建立TCP连接时,拥塞窗口被初始化为1个报文段(即另一端通告的报文段大小,也就是之前例子中的200字节)。每收到一个ACK,拥塞窗口就增加一个报文段。这里需要注意的是,虽然拥塞窗口以字节为单位,但是慢启动算法是以报文段大小为单位进行增加的。发送方取拥塞窗口与信用量窗口两者中的最小值作为发送上限。在这里,拥塞窗口是发送方使用的流量控制,而信用量窗口则是接收方使用的流量控制。发送方开始时发送一个报文段,然后等待ACK。当收到该ACK时,拥塞窗口从1增加为2,即可以发送两个报文段。当收到这两个报文段的ACK时,拥塞窗口就增加为4。因此,这是一种指数增加的关系(所谓慢启动,其实加速度很快)。
当发送方发生报文段超时重传时,就说明网络在通知发送方它的拥塞窗口开得过大,于是,发送方的拥塞窗口就会减小,退回到初始状态,以减少拥塞的发生。
3.拥塞避免算法
慢启动算法是在一个连接上发起数据流的方法,当网络拥塞时,拥塞处的中间路由器开始丢弃分组。慢启动算法无法解决中间路由器丢弃分组的情况。而拥塞避免算法是一种处理丢失分组的方法。(www.daowen.com)
该算法假定由于分组受到损坏引起的丢失是非常少的,因此分组丢失就意味着在源主机和目的主机之间的某处网络上发生了拥塞。有两种分组丢失的指示:发生超时和接收到重复的确认。
拥塞避免算法和慢启动算法是两个目的不同、独立的算法。拥塞容易,但是消除拥塞需要花很长时间。当拥塞发生时,希望降低分组进入网络的传输速率,于是可以调用慢启动来做到这一点。同时,利用拥塞避免算法动态地调整窗口大小。因此,在实际中这两个算法通常在一起实现。
拥塞避免算法和慢启动算法需要对每个连接维持两个变量:一个拥塞窗口和一个慢启动门限。这样得到的算法的工作过程如下。
1)对一个给定的连接,初始化拥塞窗口为1个报文段,慢启动门限为65535字节。
2)TCP输出例程的输出不能超过拥塞窗口和接收方信用量窗口的大小。拥塞避免是发送方使用的流量控制,而信用量窗口则是接收方进行的流量控制。前者是发送方感受到的网络拥塞的估计,而后者则与接收方在该连接上的可用缓冲区大小有关。
3)当拥塞发生时(超时或收到重复确认),慢启动门限被设置为当前窗口大小的一半(拥塞窗口和接收方信用量窗口大小的最小值,但最少为两个报文段)。
4)当新的数据被对方确认时,就增加拥塞窗口,但增加的方法依赖于是否正在进行慢启动或拥塞避免。如果拥塞窗口小于或等于慢启动门限,则正在进行慢启动,否则正在进行拥塞避免。
慢启动一直持续到回到当拥塞发生时所处位置的一半时候才停止(因为记录了在步骤2中制造麻烦的窗口大小的一半),然后转为执行拥塞避免。
慢启动算法初始设置拥塞窗口为1个报文段,此后每收到一个确认就加1。正如所说的那样,这会使窗口按指数方式增长:发送1个报文段,然后是2个,接着是4个……。
拥塞避免算法要求每次收到一个确认时将拥塞窗口增加1。与慢启动的指数增加比起来,这是一种线性增长。大家希望在一个往返时间内最多为拥塞窗口增加1个报文段,而不管在这个往返时间中收到了多少个ACK。与此对比,慢启动算法则是根据这个往返时间中所收到的确认的个数增加拥塞窗口。
4.快速恢复算法
当收到一个重复的ACK,不知道这是由一个丢失的报文段引起的,还是由于仅仅出现了几个报文段的重新排序。但如果一连串收到3个或3个以上的重复ACK,就非常可能是一个报文段丢失了。于是就重传丢失的报文段,而无需等待重传定时器超时。接下来执行拥塞避免算法。这就是快速恢复算法。
如果接下来执行慢启动算法,则称为快速重传算法。由于接收方只有在收到另一个报文段时才会产生重复的ACK,而该报文段已经离开了网络并进入了接收方的缓存。也就是说,在收发两端之间仍然有流动的数据,执行慢启动会突然减少数据流。因此,快速重传算法被快速恢复算法取代。
快速恢复算法通常按如下过程实现。
1)当收到第三个重复的ACK时,将慢启动门限设置为当前拥塞窗口的一半。重传丢失的报文段。之后设置拥塞窗口为慢启动门限加上3倍的报文段大小。
2)每次收到另一个重复的ACK时,拥塞窗口增加1个报文段大小,并发送1个报文段(如果新的拥塞窗口允许发送)。
3)当下一个确认新数据的ACK到达时,设置拥塞窗口为慢启动门限(在第1步中设置的值)。这个ACK应该是在进行重传后的一个往返时间内对步骤1中重传的确认。另外,这个ACK也应该是对丢失的分组和收到的第1个重复的ACK之间的所有中间报文段的确认。这一步采用的是拥塞避免,因为当分组丢失时会将当前的速率减半。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。