拥塞控制是对网络层面的控制,主要是为了避免发送方发送过多的数据导致网络阻塞,以及出现网络阻塞时能够调整数据发送速率,达到对网络阻塞的一个控制。
拥塞窗口cwnd,是发送方维护的一个状态变量,会根据网络的拥塞程度动态变化
发送窗口swnd和接收窗口rwdn是约等于的关系,有了拥塞窗口cwnd之后,发送窗口的值就等于min(cwnd,rwnd),也就是拥塞窗口和接收窗口的最小值
拥塞窗口cwnd的变化规则:
只要网络中没有出现拥塞,cwnd就会增大
一旦网络出现拥塞,cwnd就会减小
只要发送方没有在超时时间内接收到ACK应答报文,触发了超时重传,就会认为网络出现了拥塞。
对于网络拥塞的控制,主要通过几个算法实现:
在刚建立完TCP连接之后,会有一个慢启动的过程,而不是一上来直接发送大量的数据。
慢启动期间,【当发送方每收到一个ACK确认报文,拥塞窗口就会加1,直到窗口的大小达到慢启动门限】。慢启动门限一般是65535字节。
所以在慢启动期间,窗口大小的增长呈指数增长
当拥塞窗口大小达到慢启动门限后,就进入拥塞避免阶段,【此时发送方每收到一个ACK确认报文,拥塞窗口就增加窗口分之1的大小,也就是每收到窗口大小个ACK确认报文,窗口大小就加1】
拥塞避免阶段,窗口大小呈线性增长。
随着发送速率的增长,网络可能会出现阻塞,导致丢包,此时进入到拥塞发生阶段,这时候就需要重传数据
重传数据主要有两种机制,一种是超时重传,另一种是快速重传和快速恢复
超时重传
当发生了超时重传,就会使用拥塞发生算法:【慢启动门限会变为窗口大小的一般,拥塞窗口大小设为初始值,接着重新进入慢启动】
这种方式为了避免继续发送较多的数据而导致网络继续阻塞,而大大减少了数据的发送量
在linux系统中,我们可以使用命令来查看每一个tcp连接拥塞窗口的初始值,一般为10
ss -nli | grep cwnd
快速重传
还有另一种重传算法,也就是快速重传:当接收方发现中间丢了某一个包时,就连续发送3次丢失包的前一个包的ACK报文,于是发送方连续3次接收到相同的ACK报文,就能快速重传丢失的包,不必等到超时再重传
此时,【拥塞窗口大小变为原来的一半,慢启动门限设置为新拥塞窗口的大小,之后进入快速恢复阶段】
快速恢复
快速恢复算法如下:
拥塞窗口cwnd = 慢启动门限 + 3(3的意思是确认有3个数据包被收到了)
重传丢失的数据包
如果再收到重复的ACK,则cwnd + 1
如果收到新的ACK,则把cwnd设置为慢启动门限的值,之后进入拥塞避免阶段。(恢复过程结束,进入到恢复之前的状态)
快速重传和快速恢复算法一般同时使用
TCP协议的拥塞控制主要通过几个算法实现的,包括慢启动,拥塞避免,超时重传,快速重传和快速恢复
当TCP连接刚建立的时候,会进入【慢启动】阶段,也就是设置一个较小的拥塞窗口,发送方每收到一个ACK报文,拥塞窗口就加1,直到窗口大小达到慢启动门限
达到慢启动门限后,就进入【拥塞避免】阶段,发送方每收到拥塞窗口大小个ACK报文,窗口大小就加1
随着拥塞窗口大小,也就是发送速率的不断增加,网络可能会出现拥塞导致丢包,此时就需要重传数据,【重传】主要有两种机制
一种是超时重传,此时慢启动门限会设置为拥塞窗口的一半,窗口大小恢复为初始值,接着重新进入慢启动,发送速率就会瞬间下降很多
另一种是快速重传和快速恢复,当发送方连续接收到重复的ACK报文时,就认为发生丢包,此时拥塞窗口就会设置为原来的一般,慢启动门限设置为原来的一半,随后进入快速恢复阶段。快速恢复阶段会重传丢失的报文,当收到ACK后,拥塞窗口设置为慢启动门限,接着进入拥塞避免阶段。
这些拥塞控制算法能够防止一下子发送过多的数据导致网络拥塞,以及出现网络拥塞时及时调整数据的发送速率。