(十六)TCP保证可靠性之拥塞控制
拥塞控制就是为了防止过多的数据注入到网络中,这样就可以使网络中的路由器或链路不致过载。
TCP的拥塞控制采用了四种算法,即 慢开始 、 拥塞避免 、快重传 和 快恢复。
(简记这两个过程:门限下是慢启动,门限上是拥塞避免,出现拥塞则门限减半,再慢启动)
慢启动算法的思路:主机开始发送数据报时,如果立即将大量的数据注入到网络中,可能会出现网络的拥塞。慢启动算法就是在主机刚开始发送数据报的时候先探测一下网络的状况,如果网络状况良好,发送方每发送一次文段都能正确的接受确认报文段。那么就从小到大的增加拥塞窗口的大小,即增加发送窗口的大小。
开始发送方先设置cwnd(拥塞窗口)=1,发送第一个报文段M1,接收方接收到M1后,发送方接收到接收方的确认后,把cwnd增加到2,接着发送方发送M2、M3,发送方接收到接收方发送的确认后cwnd增加到4,慢启动算法每经过一个传输轮次(认为发送方都成功接收接收方的确认),拥塞窗口cwnd就加倍。
指数增长理解:
①最开始cwnd=1,发送方只发送一个mss大小的数据包,在一个rtt后,会收到一个ack,cwnd加一,cwnd=2
②此时cwnd=2,则发送方要发送两个mss大小的数据包,发送方会收到两个ack,则cwnd会进行两次加一的操作,则也就是cwnd+2,则cwnd=4,也就是cwnd = cwnd * 2
③此时cwnd=4,则发送方要发送四个mss大小的数据包,发送方会收到四个ack,则cwnd会加4,则 cwnd = 8,也就是cwnd = cwnd * 2.
以此类推,在每次rtt后,cwnd都会变成一次数据包发送前的cwnd的两倍,这是一个等比数列,则此等比数列的推导公式就是cwnd(n) = cwnd(1) * 2^(n-1) . n>=1
拥塞避免:为了防止cwnd增加过快而导致网络拥塞,所以需要设置一个慢开始门限ssthresh状态变量,它的用法:
1. 当cwnd < ssthresh,使用慢启动算法,
2. 当cwnd > ssthresh,使用拥塞控制算法,停用慢启动算法。
3. 当cwnd = ssthresh,这两个算法都可以。
拥塞避免的思路:是让cwnd缓慢的增加而不是加倍的增长,每经历过一次往返时间就使cwnd增加1,而不是加倍,这样使cwnd缓慢的增长,比慢启动要慢的多。
无论是慢启动算法还是拥塞避免算法,只要判断网络出现拥塞,就要把慢启动开始门限(ssthresh)设置为设置为发送窗口的一半(>=2),cwnd(拥塞窗口)设置为1,然后在使用慢启动算法,这样做的目的能迅速的减少主机向网络中传输数据,使发生拥塞的路由器能够把队列中堆积的分组处理完毕。拥塞窗口是按照线性的规律增长,比慢启动算法拥塞窗口增长块的多。
实例:1.TCP连接进行初始化的时候,cwnd=1,ssthresh=16(报文最大数据长度)。
2.在慢启动算法开始时,cwnd的初始值是1,每次发送方收到一个ACK拥塞窗口就增加1,当ssthresh =cwnd时,就启动拥塞控制算法,拥塞窗口按照规律增长(拥塞避免)
3.当cwnd=24时,网络出现超时(出现拥塞),发送方收不到确认ACK,此时设置ssthresh=12,(二分之一cwnd),设置cwnd=1,然后开始慢启动算法,当cwnd=ssthresh=12,慢启动算法变为拥塞控制算法,cwnd按照线性的速度进行增长。
快重传和快恢复(是针对收到3个重复ACK情况)
- 快速重传算法:如果一连串收到3个或3个以上的重复ACK,就非常可能是一个报文段丢失了。于是我们就重传丢失的数据报文段,而无需等待超时定时器溢出。
- 快速恢复算法:快速重传后执行的不是慢启动算法而是拥塞避免算法
- 在拥塞举例中:在这种情况下没有做执行慢启动的原因是由于收到重复的ACK不仅仅告诉我们一个分组丢失了。由于接收方只有在收到另一个报文段时才会产生重复的ACK,而该报文段已经离开了网络并进入了接收方的缓存。也就是说,在收发两端之间仍然有流动的数据,而不是我们不想执行慢启动来突然减少数据流
(简单来说,就是因为网络等原因丢了,而不是我处理不过来丢的)
快恢复:
1. 当发送发连续接收到三个确认时,就执行乘法减小算法,把慢启动开始门限(ssthresh)减半,但是接下来并不执行慢开始算法。
- 此时不执行慢启动算法,而是把cwnd设置为ssthresh的一半, 然后执行拥塞避免算法,使拥塞窗口缓慢增大。