TCP拥塞控制机制

来源:互联网 发布:手机数据线线芯排序 编辑:程序博客网 时间:2024/04/30 02:49

原文地址:http://blog.sina.com.cn/s/blog_48ebca64010003t0.html

研究TCP的拥塞机制,不仅仅是想了解TCP如何的精巧,更多的是领悟其设计思想,即在一般情况下,我们该怎样处理问题。

一.拥塞的发生与其不可避免
拥塞发生的主要原因在于网络能够提供的资源不足以满足用户的需求,这些资源包括缓存空间、链路带宽容量和中间节点的处理能力。由于互联网的设计机制导致其缺乏“接纳控制”能力,因此在网络资源不足时不能限制用户数量,而只能靠降低服务质量来继续为用户服务,也就是“尽力而为”的服务。
但是,是不是说只要增加网络资源,就能避免拥塞呢?答案却是否定的!拥塞虽然是由于网络资源的稀缺引起的,但单纯增加资源并不能避免拥塞的发生。例如增加缓存空间到一定程度时,只会加重拥塞,而不是减轻拥塞,这是因为当数据包经过长时间排队完成转发时,它们很可能早已超时,从而引起源端超时重发,而这些数据包还会继续传输到下一路由器,从而浪费网络资源,加重网络拥塞。事实上,缓存空间不足导致的丢包更多的是拥塞的“症状”而非原因。另外,增加链路带宽及提高处理能力也不能解决拥塞问题。
例如:我们有四台主机ABCD连接路由器R,所有链路带宽都是1Gbps,如果A和B同时向C以1Gbps的速率发送数据,则路由器R的输入速率为2Gbps,而输出速率只能为1Gbps,从而产生拥塞。避免拥塞的方法只能是控制AB的速率,例如,都是0.5Gbps,但是,这只是一种情况,倘若D也向R发送数据,且速率为1Gbps,那么,我们先前的修正又是不成立的,可见,拥塞其实是一个动态问题,我们没有办法用一个静态方案去解决,从这个意义上来说,拥塞是不可避免的。

二.流量控制
早期的TCP协议只有基于窗口的流控制(flow control)机制,我们简单介绍一下,并分析其不足。
在TCP中,为了实现可靠性,发送方发出一个数据段之后要等待接受方相应的确认信息,而不是直接发送下一个分组。具体的技术是采用滑动窗口,以便通信双方能够充分利用带宽。滑动窗口允许发送方在收到接收方的确认之前发送多个数据段。窗口大小决定了在收到目的地确认之前,一次可以传送的数据段的最大数目。窗口大小越大,主机一次可以传输的数据段就越多。当主机传输窗口大小数目的数据段后,就必须等收到确认,才可以再传下面的数据段。例如,若视窗的大小为 1,则传完数据段后,都必须经过确认,才可以再传下一个数据段;当窗口大小等于3时,发送方可以一次传输3个数据段,等待对方确认后,再传输下面三个数据段。
窗口的大小在通信双方连接期间是可变的,通信双方可以通过协商动态地修改窗口大小。在TCP的每个确认中,除了指出希望收到的下一个数据段的序列号之外,还包括一个窗口通告,通告中指出了接收方还能再收多少数据段(我们可以把通告看成接收缓冲区大小)。如果通告值增大,窗口大小也相应增大;通告值减小,窗口大小也相应减小。但是我们可以发现,接收端并没有特别合适的方法来判断当前网络是否拥塞,因为它只是被动得接收,不像发送端,当发出一个数据段后,会等待对方得确认信息,如果超时,就可以认为网络已经拥塞了。所以,改变窗口大小的唯一根据,就是接收端缓冲区的大小了。
流量控制作为接受方管理发送方发送数据的方式,用来防止接受方可用的数据缓存空间的溢出。流控制是一种局部控制机制,其参与者仅仅是发送方和接收方,它只考虑了接收端的接收能力,而没有考虑到网络的传输能力;而拥塞控制则注重于整体,其考虑的是整个网络的传输能力,是一种全局控制机制。正因为流控制的这种局限性,从而导致了拥塞崩溃现象的发生。

三.重传
1、一旦收到确认,发送方关闭重发定时器并且将数据片的备份从重发队列中删除。发送方如果在规定的时间内没有收到数据确认,就重传该数据。
2、当TCP超时并重传时,它不一定要重传同样的报文段,相反,TCP允许进行重新分组而发送一个较大的报文段,这将有助于提高性能(当然,这个较大的报文段不能够超过接收方声明的MSS)。在协议中这是允许的,因为TCP是使用字节序号而不是报文段序号来进行识别它所要发送的数据和进行确认。
3、重发定时器
(1) 每一次一个包含数据的包被发送(包括重发),如果该定时器没有运行则启动它,使得它在RTO秒之后超时(按照当前的RTO值)。
(2) 当所有的发出数据都被确认之后,关闭该重发定时器。
(3) 当接收到一个ACK确认一个新的数据,重新启动该重发定时器,使得它在RTO秒之后超时(按照当前的RTO值)

四.TCP拥塞控制机制
TCP的拥塞控制由4个核心算法组成:“慢启动”(Slow Start)、“拥塞避免”(Congestion voidance)、“快速重传 ”(Fast Retransmit)、“快速恢复”(Fast Recovery)。具体的流程图可以参见:http://www.eventhelix.com/RealtimeMantra/Networking/,这里我会把自己的理解尽可能详细的列出来。为了方便起见,把发送端叫做client,接收端为server,每个segment长度为512字节,阻塞窗口长度为cwnd(简化起见,下面以segment为单位),sequence number为seq_num,acknowledges number为ack_num。通常情况下,TCP每接收到两个segment,发送一个ack。

-- 慢启动
早期开发的TCP应用在启动一个连接时会向网络中发送大量的数据包,这样很容易导致路由器缓存空间耗尽,网络发生拥塞,使得TCP连接的吞吐量急剧下降。由于TCP源端一开始并不知道网络资源当前的利用状况,因此新建立的TCP连接不能一开始就发送大量数据,而只能逐步增加每次发送的数据量,以避免上述现象的发生,这里有一个“学习”的过程。
假设client要发送5120字节到server,慢启动过程如下:
1.初始状态,cwnd=1,seq_num=1;client发送第一个segment;
2.server接收到512字节(一个segment),回应ack_num=513;
3.client接收ack(513),cwnd=1+1=2;现在可以一次发送2个数据段而不必等待ack
4.server接收到2个segment,回应ack_num=513+512*2=1537
5.client接收ack(1537),cwnd=2+1;一次发送3个数据段
6.server接收到3个segment,回应2个ack,分别为ack_num=1537+1024=2561和ack_num=2561+512=3073
7.client接收ack(2561)和ack(3073),cwnd=3+2=5;一次可以发送5个数据段,但是只用4个就满足要求了
8.server接收到4个segment,回应2个ack,分别为4097,5121
9.已经发送5120字节,任务完成!

总结一下:
当建立新的TCP连接时,拥塞窗口(congestion window,cwnd)初始化为一个数据包大小。源端按cwnd大小发送数据,每收到一个ACK确认,cwnd就增加一个数据包发送量。

-- 拥塞避免
可以想象,如果按上述慢启动的逻辑继续下去而不加任何控制的话,必然会发生拥塞,引入一个慢启动阈值ssthresh的概念,当cwnd

0 0
原创粉丝点击