TCP拥塞控制

一、背景介绍

  两台主机在传输数据包的时候,如果发送方迟迟没有收到接收方反馈的ACK,那么发送方就会认为它发送的数据包丢失了,进而会重新传输这个丢失的数据包。然而实际情况有可能此时有太多主机正在使用信道资源,导致网络拥塞了,而A发送的数据包被堵在了半路,迟迟没有到达B。这个时候A误认为是发生了丢包情况,会重新传输这个数据包。这样不仅浪费了信道资源,还会使网络更加拥塞。
  拥塞控制的出现,减少了网络拥堵,促使网络尽快回复正常。

1、名次解释

  • MSS:最大报文长度,这里指报文数据的大小
  • ssthresh :慢启动阈值(slow start threshold)
  • cwnd:拥塞窗口(Congestion Window),表示一次性连续发送多少个MSS数据包
  • RTT:数据完全发送完到收到确认信号的时间
  • RTO:超时重传

二、拥塞控制的算法

拥塞控制主要由四个算法组成:

  • 慢启动(Slow Start)
  • 拥塞避免(Congestion Avoidance)
  • 快速重传
  • 快速恢复(Fast Recovery)
    在这里插入图片描述

1、慢启动

  慢启动的机制:当TCP连接建立之后,cwnd的大小被初始化为1个最大报文段(MSS)的大小。发送方每收到一次ACK确认之后,就将cwnd的大小增加一个报文段。增加规则如下:cwnd += min(N,MSS),N为上次发送被确认的字节数。

慢启动存在的理由是:tcp刚开始并不知道网络的实际情况,需要用一种试探性的方式平滑的增加cwnd的大小。慢启动算法增加了拥塞窗口,可以反应网络的整体情况,而滑动窗口只能反应主机个体情况。

  从上述cwnd的增加规则中可以看出,慢启动中cwnd的大小是呈指数级增长的。因此,慢启动并不慢。如果不进行控制,慢启动最终会导致网络拥塞。为了防止这种情况的发生,TCP在拥塞控制中增加了一个变量ssthresh。并且规定了cwnd的大小要按照下述规则进行:

当cwnd<ssthresh时:进行慢启动算法
当cwnd>ssthresh时:进行拥塞避免算法
当cwnd==ssthresh时::两种皆可

2、拥塞避免

  cwnd>ssthresh时,进行拥塞避免。拥塞避免即让cwnd缓慢的增长,在一个RTT时间内,将cwnd的大小增加1,即增加cwnd的初始大小。这样,cwnd的大小就从以前的指数级增长变成现在的线性增长。

无论是慢开始还是拥塞避免,只要网络出现阻塞,就将ssthresh的值更新为cwnd的一半,但不能小于2。同时将cwnd的大小更新为1,即为cwnd的初始大小。

3、快速重传

  当发送端连续收到3个重复的确认报文端段(3个重复,所以一共收到4个)的时候,tcp就认为拥塞发生了,然后会立即重传丢失的报文段。这个机制不需要等到重传定时器超时,所以叫做快速重传。
此时,

  • cwnd大小缩小为当前的一半
  • ssthresh设置为缩小后的cwnd大小
  • 然后进入快速恢复算法

在TCP报文段丢失或者接收端收到乱序的TCP报文段等情况下,发送端都会收到重复的确认报文段。

4、快速恢复

  在进入快速恢复之前,cwnd和ssthresh已经被更改为原有cwnd的一半,即sstresh=cwnd/2

  • 设置:cwnd = ssthresh+3*MSS,加3 * MSS的原因是因为收到3个重复的ACK
  • 重传DACKs指定的数据包
  • 如果再收到DACKs,那么cwnd大小增加一
  • 如果收到新的ACK,表明重传的包成功了,那么退出快速恢复算法。将cwnd设置为ssthresh,然后进入拥塞避免算法

三、拥塞控制的状态机

在这里插入图片描述

1、Open状态

  拥塞控制状态机的默认状态。这种状态下,当ACK到达时,发送方根据拥塞窗口cwnd是小于还是大于慢启动阈值ssthresh,来按照慢启动或者拥塞避免算法来调整拥塞窗口。

2、Disorder状态

  当发送方检测到DACK(重复确认)或者SACK(选择性确认)时,状态机将转变为Disorder状态。在此状态下,发送方遵循飞行(in-flight)包守恒原则,即一个新包只有在一个老包离开网络后才发送,也就是发送方收到上一个包的ACK后,才会再发送下一个包。

3、CWR状态

  发送方接收到一个拥塞通知时,并不会立刻减少拥塞窗口cwnd,而是每收到两个ACK就减少一个段,直到窗口的大小减半为止。当cwnd正在减小并且网络中有没有重传包时,这个状态就叫CWR(Congestion Window Reduced,拥塞窗口减少)状态。CWR状态可以转变成Recovery或者Loss状态。

4、Recovery状态

  当发送方接收到足够(推荐为三个)的DACK(重复确认)后,进入该状态。在该状态下,拥塞窗口cnwd每收到两个ACK就减少一个段(segment),直到cwnd等于慢启动阈值ssthresh,也就是刚进入Recover状态时cwnd的一半大小。 发送方保持 Recovery 状态直到所有进入 Recovery状态时正在发送的数据段都成功地被确认,然后发送方恢复成Open状态,重传超时有可能中断 Recovery 状态,进入Loss状态。

5、Loss状态

  当一个RTO到期后,发送方进入Loss状态。所有正在发送的数据标记为丢失,拥塞窗口cwnd设置为一个段(segment),发送方再次以慢启动算法增大拥塞窗口cwnd。
  Loss 和 Recovery 状态的区别是:Loss状态下,拥塞窗口在发送方设置为一个段后增大,而 Recovery 状态下,拥塞窗口只能被减小。Loss 状态不能被其他的状态中断,因此,发送方只有在所有 Loss 开始时正在传输的数据都得到成功确认后,才能退到 Open 状态。

### TCP拥塞控制原理 TCP拥塞控制旨在防止过多的数据涌入网络,从而避免引发网络拥塞。该过程通过调整发送方的发送速率来适应当前网络条件的变化。主要目标是在最大化吞吐量的同时最小化延迟丢包率。 #### 主要机制 1. **慢启动** 发送方初始时会设置一个较小的窗口大小(即cwnd),随着每一轮成功的传输逐步增加这个值直到遇到第一个丢包事件为止[^1]。 2. **拥塞避免** 当达到一定阈值后进入线性增长阶段,每次成功接收ACK反馈只按固定增量扩大拥塞窗口;一旦检测到超时或重复ACK,则认为发生了拥塞并采取相应措施减少流量输出[^2]。 3. **快速重传与恢复** 如果接收到三个以上的重复ACK,表明有未被确认的数据段可能已经丢失,此时立即触发重发而不必等待完整的计时器到期。这有助于加快错误修复速度,并保持较高的链路利用率[^3]。 4. **加法增大/乘法减小 (AIMD)** 这种策略用于调节拥塞窗口的增长方式:正常情况下采用缓慢而稳定的速度递增(cwnd += MSS),而在发生拥塞迹象时则急剧收缩(cwnd /= 2)。 ### C++实现示例 下面给出一段简单的C++伪代码片段展示如何模拟上述部分逻辑: ```cpp class TCPSender { private: int cwnd; // 拥塞窗口大小 double ssthresh; // 慢启动门限 public: void handle_ack() { if (in_slow_start()) { cwnd *= 2; } else { cwnd++; } if (detect_congestion()) { fast_retransmit(); cwnd = max(1, static_cast<int>(cwnd / 2)); ssthresh = cwnd; } } bool in_slow_start() const { return cwnd < ssthresh; } void fast_retransmit() { // 实际应用中应在此处处理具体的重传操作 } bool detect_congestion() const { // 此函数应该根据实际情况判断是否存在拥塞现象 return false; } }; ``` 这段代码展示了基本框架下的几个核心功能模块,包括但不限于响应ACK消息更新拥塞窗口、执行快速重传以及识别潜在的拥塞状况等。 ### 新兴算法简介 除了传统的基于损失的传统方法外,还有像BBR这样的现代方案试图利用更丰富的信息源来进行更加精准有效的带宽估计与优化调度工作。尽管如此,由于实际环境复杂多变,单一模式难以满足所有场景需求,因此研究者们也在探索混合型解决方案的可能性[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值