本作是自己看书总结出来的,如有不正,请各位大佬指点一二
所谓拥塞控制,就是防止过多的数据注入到网络,使得网络中的通信设备和通信线缆不会因为过载而导致网络性能大大下降。
网络中通信设备具有数据处理转发性能、通信链路具有的传输带宽,而其中某台性能差的设备包处理性能或链路的最小带宽就是这个网络可用来传输数据的最大带宽。如果传输的数据量过大,超过网络的承载范围,那么不可避免的会出现网络拥塞,从而导致丢包现象。拥塞控制就是通过调节网络中传输的数据量使其在最大传输带宽以下,保证数据的正常传输。
TCP的拥塞控制有以下四种方法:
- 慢启动
- 拥塞避免
- 快速重传
- 快速恢复
1.慢启动
慢启动是基于发送端所做的拥塞控制,大致思想是试探性的发送数据,由小逐渐增大数据的发送量。而发送方发送数据是通过发送窗口发送的,一次性可发送多少数据是由发送窗口的大小决定的。这个窗口在这里有个特殊名词——拥塞窗口(cwnd)。RFC5681规定,cwnd的初始值不超过2-4个SMSS(发送方最大报文段)。
cwnd计算公式如下(适用于拥塞避免):
c
w
n
d
+
=
M
S
S
∗
M
S
S
/
c
w
n
d
cwnd += MSS*MSS/cwnd
cwnd+=MSS∗MSS/cwnd
解释一下就是,发送方发出去n个数据包的同时期望收到n个ACK确认报文。在收到ACK确认报文的同时增大cwnd大小,假设cwnd当前值是n个MSS
,那么在其发送出n个MSS
后,每收到一个ACK报文cwnd就增加MSS*MSS/cwnd
,当收到n个ACK报文后增加n*(MSS*MSS/cwnd)
。
慢启动的运行原理是通过设置一个初始cwnd大小为m,先尝试发送m个MSS,当收到来自接收方回复的m个ACK确认包则会将原来的cwnd增大,增大过程其实就是进行加1操作,即每收到一个ACK确认包就进行加1,当收到m个确认包后原cwnd的大小就会增长到2m。
说明:实际上发送窗口的传输单位是字节,这里便于解释说明采用MSS为单位,设MSS=1460bytes,在经过底层封装后(封装20字节的TCP头部和20字节的IP头部)数据包大小达到1500字节,假设中间所有设备以及接收端都能接收转发该大小的MSS。
如上图所示:
- cwnd的初始值为1,发送方发送出去一个报文段并成功接收到来自接收方回复的ACK确认包。当发送方收到确认报文后就可以知道当前网络是能承载一个MSS,因此发送方尝试加大报文段发送量,于是将cwnd窗口进行加1操作,cwnd大小由起始的1变成了2;
- 继续传送剩下的数据包,此时由于cwnd=2因此发送端会发出2个MSS,当发送方接收到接收方回复的2个ACK确认包时,又将尝试增加数据发送量,再次进行加1操作,cwnd大小由2变成了4;
- 由于cwnd=4,此时将发出4个MSS,发送方接收到接收方回复的4个ACK确认包时,又将尝试增加数据发送量,再次进行加1操作,cwnd大小由4变成了8;
- 当网络没有出现丢包情况,该操作就会一直持续到cwnd=ssthresh(慢启动门限)为止,然后进行线性增长。
那么如果在cwnd增长过程中网络质量差,出现了丢包的情况怎么办呢?
通过超时重传和快速重传,重新调整cwnd大小以及慢启动门限值。
2.拥塞避免
前面介绍的慢启动算法虽然名字中有个“慢”,但并不代表它启动慢。此“慢”非彼“慢”,慢启动算法的这个“慢”是指它的初始值设置的小,最大只有4个MSS最小只有1个MSS,相对一开始就将所有的数据包都注入网络要来的慢。慢启动算法在网络无故障时cwnd的增长都是乘2增长的,这也意味着cwnd发送的报文段也是成倍增长的,因此会导致传输量一下就达到最大承载量从而造成网络拥塞。然后cwnd会调整到初始值,又开始执行慢启动算法,当达到最大承载量又调整cwnd大小,如此周而复始导致网络速率及其不稳定,时大时小,严重影响网络性能。
因此出现了拥塞避免算法,它的增长量相对于慢启动的指数增长要平缓的多,它是按RTT缓慢增长的,每经过一个RTT cwnd就增长1,当cwnd达到慢启动门限时就开始启用拥塞避免算法。
cwnd和ssthresh的关系:
cwnd < ssthresh:执行慢启动算法
cwnd = ssthresh:慢启动算法和拥塞避免算法都可
cwnd > ssthresh:执行拥塞避免算法
上图反应了cwnd的大小与RTT之间的变化:
cwnd的初始值设置为1,ssthresh的初始值设置为16
- cwnd的初始值为1,ssthresh=12,cwnd < ssthresh,执行慢启动算法,经过4个RTT的增长,cwnd增长到16;
- 此时cwnd = ssthresh,cwnd的继续增长并开始执行拥塞避免算法,cwnd开始平缓增长。
- 随着cwnd增长到24,此时网络出现了丢包触发了超时重传机制,cwnd调整为1,ssthresh=cwnd/2=12
- 此时cwnd=1,ssthresh=12,cwnd < ssthresh;又开始执行慢启动算法
- 当cwnd=ssthresh=12时,开始执行拥塞避免算法
- 当cwnd = 16时,此时发送方收到了3个连续duplicated ACK报文,触发快速重传机制
- 快速重传调整ssthresh=cwnd/2,cwnd=ssthresh后直接进入拥塞避免,这就是快速恢复算法
拥塞控制的各个状态之间的转换图
3.快速重传和快速恢复
TCP传输数据时,发送端发送一个数据包给接收端,当接收端收到该数据包时需要给发送端回复一个ACK确认包以告诉发送方收到了该数据包。快速重传算法就是利用了TCP的这个特点,它在发送方发送的报文有丢失或报文未按序到达的情况下,而又收到了该数据包的下个包,那么接收方主动发送ACK报文确认已经收到该报文之前的上一个报文,当发送方连续收到三个(也称作duplicated ACK)ACK报文时,发送方就知道了该报文没有被接收端接收,于是重传该报文。
上图指证个错误,ack7确认包没有,这条线去掉,由于之前的重复确认包已经确认了d6,因此只会发出ack8确认7号包
如上图所示,发送方向接收方发送了2个包D1、D2,接收方正常接收并向发送方回复了ACK报文,接下来继续发送D3、D4,但是D3在传输过程中丢失了,因此接收方收不到D3,在收到D4时接收方发现不是D3,于是并向接收方回复duplicated ACK3重复确认收到D2报告D3没有收到。发送方收到第1个重复确认包不予理会,继续发送D5、D6,当D5、D6到达接收方时,接收方发现还不是D3,于是继续回复duplicated ACK3报告D3未收到,由于此时收到了D5、D6两个包,因此会回复2个duplicated ACK3,此时发送方总共收到3个连续的duplicated ACK3,因此立即重传D3,当接收方收到D3后正常回复ACK7,因为前6个报文都已收到。
为什么需要重传3次,而不是2次、4次?
还是拿上面的图来分析,当接收端没有收到D3,此时有3种情况:
- D3传输乱序,导致后续的包先于D3到达
- D3传输延时
- D3在传输过程中被丢弃了
那么我们就需要判断到底是哪种情况导致的D3没有到达,判断依据就是发送duplicated ACK
1)发送方收到1个D2 duplicated ACK
此时接收方收到的包顺序可能是如下顺序:
- D1、D2、D4、D3、D5、D6 、D7
- D1、D2、D5、D3、D4、D6 、D7
- D1、D2、D6、D3、D5、D4、D7
2)发送方收到2个D2 duplicated ACK
- D1、D2、D5、D4、D3、D6 、D7
- D1、D2、D5、D6、D3、D4、D7
- D1、D2、D6、D7、D3、D5、D4
- …
3)发送方收到3个D2 duplicated ACK
- D1、D2、D5、D4、D6 、D3、D7
- D1、D2、D5、D7、D4、D3、D4
- D1、D2、D6、D7、D4、D3、D5
- …
4)发送方收到4个D2 duplicated ACK
- D1、D2、D5、D4、D6 、D7、D3
- D1、D2、D5、D7、D4、D4、D3
- D1、D2、D6、D7、D4、D5、D3
当发送方接收到1个duplicated ACK一定是传输乱序,2个duplicated ACK大概率是乱序,而3个duplicated ACK就可能是超时或者丢包了,4个duplicated ACK就更不用说了基本是丢包了。因此采用3次最好,这也是实际运用中测试总结出来的。不过有没有可能在接收方回复了3个duplicated ACK之后收到了原来的包,这个是有可能的,当网络过于拥塞或者QOS策略导致该包的转发时延过长,但是这个概率是很低的。
最后再来说说快速恢复,当拥塞窗口由于快速重传导致重新调整,由于快速重传并没有发生拥塞,它只是由单个包丢失引起的。因此所作调整也不一样,此时重新调整后的sshthresh = cwnd/2,cwnd = ssthresh。然后直接进入拥塞避免阶段(cwnd = ssthresh)。也有的快速恢复是把cwnd = ssthresh + 3*MSS,原理是在快速重传阶段由于接收方发送了3个重复ACK,会使得网络中有3个包离开进入到接收方的缓存,因此可以将其适当的扩大。
超时重传和快速重传:
超时重传是发送端主动进行的的重传,基于收不到ACK报文。当数据包经由发送端发送出去以后,超过了一个RTO后还未收到接收端的ACK报文,就认为数据包丢失,随即在重传一次
快速重传是由接收端主动进行的,基于能收到ACK报文,但是需要后续报文做辅助,如果发送的报文恰好是最后一个那么只能等到RTO计时器耗尽后,发送端进行重传。数据包经由发送端发送出去以后,当第N个报文被收到而第N-1个报文乱序或者丢失导致报文没有被收到,接收方每收到一个后续报文就重传一次duplicated ACK,报告未收到第N个报文,发送方收到前两个duplicated ACK会再“等等”以防止是乱序或者延时导致的,当收到第3个duplicated ACK时,发送方就会立即重传第N个报文。文章来源:https://www.toymoban.com/news/detail-512010.html
乱序或者丢失导致报文没有被收到,接收方每收到一个后续报文就重传一次duplicated ACK,报告未收到第N个报文,发送方收到前两个duplicated ACK会再“等等”以防止是乱序或者延时导致的,当收到第3个duplicated ACK时,发送方就会立即重传第N个报文。文章来源地址https://www.toymoban.com/news/detail-512010.html
到了这里,关于TCP拥塞控制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!