1. TCP拥塞控制
动态调整数据传输速率,在网络好的时候提高发送速度,在网络不好的时候减少发送速度,这样在最大化利用带宽的同时并保证数据传输的可靠性,这就是拥塞控制的业务了,在拥塞控制的标准文档中(RFC 5681)中描述了拥塞控制的4个部分,或者说4种状态,拥塞控制就是4种状态之间的切换。
- 慢启动
- 拥塞避免
- 快速重传
- 快速恢复
但是要注意了,标准没有规定4种状态都要实现,取决于具体的算法设计思路,Linux内核中提供了多种实现,我当前的系统是Ubuntu24.4,使用的是:cubic算法。
|
|
这个拥塞控制,到底控制了个啥呀,这时候要先提3个概念:RWDN(接收通告窗口)、CWDN(拥塞窗口)、SWDN(Send Window,发送窗口)。
- RWND:接收方通过这个东西告诉发送方,它的TCP接收缓存区还能容纳多少字节的数据。
- CWND:拥塞窗口,拥塞控制直接控制这个变量。
- SWND:RWND、CWND两者的最小值。
拥塞控制这一套最终的目的就是控制SWDN的大小。从另一个角度理解SWND,TCP采用发送应答机制,每一个发送出去的数据报文,都要接收对方的应答报文,以此来确保对方确实收到了数据。如果说每次发送数据后,非要等到收到对方的应答报文后才能发送下一个报文,那网络就卡到爆炸了。所以TCP协议允许一次性发送多个报文,这个一次性发送的数据量就是发送窗口。现在我们知道了RWND来自于接收方,那么CWND如何获取呢?
在一些书籍上,将SWND计算分为两种情况: 1.发生拥塞前的拥塞控制 2.发生拥塞后的拥塞控制。
1.1. 发生拥塞前的拥塞控制
预防性拥塞避免,这种情况下的拥塞控制有两个阶段:慢启动、拥塞避免。在TCP连接建立后,CWND会有一个初始值,内核版本不同这个初始值可能也会不同。慢启动处于刚开始发送数据的时候,实际上它也不慢,以指数形式增加CWDN,每收到一个ACK就增加一次。但是会受到慢启动门限的限制,当CWND大于慢启动门限时就会进入拥塞避免状态,而拥塞避免采用线性的方法增加CWND。
1.2. 发生拥塞后的拥塞控制
首先我们要判断拥塞是否发生了,有两种判断依据:传输超时、接收到重复的确认报文段。两种情况使用的拥塞控制方法也不同。
1. 传输超时,或者收到重复报文段发生在超时后面:这种情况使用的还是“慢启动->拥塞避免”的套路。如果判断是这种情况,就会将CWDN设置为一个小于慢启动门限制的值,如此一来,拥塞控制就会进入慢启动状态了。
2. 接收到重复ACK报文: 使用快速重传->快速恢复的套路。检测到这种事件,会立即重传丢失的报文,也就是快速重传,重传后会将CWND设置为一个大于慢启动门限的值,之后每次收到一个重复的ACK,SWND就增加一个SMSS,直到收到新数据的ACK时,将CWND设置为慢启动门限,这就是快速恢复,之后就会进入拥塞避免状态了。
2. 其他
SMSS: TCP报文段数据部分的最大长度。