Post

深入理解 TCP 的流量控制与拥塞控制

深入理解 TCP 的流量控制与拥塞控制

深入理解 TCP 的流量控制与拥塞控制

在网络通信中,TCP(Transmission Control Protocol,传输控制协议) 是最常用、最基础的传输层协议之一。它负责在不可靠的网络上提供 可靠的数据传输。 为保证数据既不丢、不乱,又能尽量高效地传输,TCP 引入了许多机制,其中最重要的两个是:

  • 流量控制(Flow Control)
  • 拥塞控制(Congestion Control)

这两个机制名字相似,但解决的问题完全不同。

1. 为什么需要流量控制?

1.1 接收方处理能力有限

设想一个场景:发送方(Sender)是一台性能很强的服务器,而接收方(Receiver)是一台老旧的电脑。

如果发送方以极快的速度连续发包,接收方的缓存区(Buffer)来不及处理这些数据,缓冲区会被填满。 当新数据还在源源不断地到达,就会出现:

  • 缓冲区溢出(Buffer Overflow)
  • 数据被丢弃(数据还没来得及处理就被覆盖)

导致虽然 TCP 是“可靠传输协议”,但由于接收方过载,可靠性也会失效。

1.2 流量控制的目标

让发送方的发送速率不要超过接收方的接收速率。

流量控制是“点对点”的控制机制,控制的是“发送方—接收方”之间的流速匹配问题。

2. 流量控制的实现

2.1 实现机制:滑动窗口(Sliding Window)

TCP 使用 接收窗口(rwnd, receive window) 来实现流量控制。

2.1.1 工作原理

  1. 接收方在 TCP 报文首部中会告诉发送方: 「我当前还能接收的数据量是多少(即窗口大小 rwnd)」
  2. 发送方根据这个窗口大小,限制自己可以连续发送的数据量。
  3. 当接收方处理完一部分数据后,会更新 rwnd,让发送方继续发。

2.1.2 工作流程

(1) 发

发送方可以发送窗口内所有“未发送且可发送”的数据(比如这里的 6)。

(2) 等

当接收方收到数据后,会返回一个新的 ACK,告知:“我已经收到某个序号前的所有数据。”

(3) 滑

发送方收到新的 ACK 后,会:

  • 把窗口下边界右移(因为旧数据已确认);
  • 并将窗口上边界也右移(新的数据可以发了)。

当接收方缓冲区满时,可能会通告 win=0,这意味着:“暂时不要再发数据了。”

此时发送方会暂停发送,进入零窗口探测(Zero Window Probe)模式,定期探测接收方是否恢复接收能力。

3. 为什么需要拥塞控制?

3.1 网络链路资源有限

即使接收方能处理得很快,也不代表整个网络能承受那么多流量。

想象一条路上只有两车道,如果大家都疯狂往路上开车,就会出现:

  • 网络中路由器缓存被填满(队列溢出)
  • 数据包被丢弃(丢包)
  • 重传增多,进一步加剧网络拥塞

最终结果是:整个网络都慢下来了。

3.2 拥塞控制的目标

防止过多的数据注入网络,从而避免网络发生拥塞。

流量控制是 “端到端” 的速率匹配问题;拥塞控制是 “整个网络” 的负载平衡问题。

3.3 拥塞控制的基本思想

TCP 通过检测网络状态(主要是“是否丢包”)来动态调整发送速率。 它引入了一个新的控制变量:拥塞窗口(cwnd, congestion window)

发送方实际能发送的数据量取决于:min(rwnd, cwnd)

  • 不超过接收方的接收能力;
  • 不超过网络的承载能力。

4. 拥塞控制的实现

TCP 拥塞控制主要经历了四个阶段:

阶段名称作用
1慢启动(Slow Start)快速探测网络容量
2拥塞避免(Congestion Avoidance)逐步增加速率,避免过载
3快重传(Fast Retransmit)发现丢包时快速重传
4快恢复(Fast Recovery)避免重启慢启动,平滑恢复速率

4.1 慢启动(Slow Start)

名字虽然叫“慢启动”,其实是“指数级增长”的。

  • 初始化 cwnd = 1 MSS(最大报文段大小)
  • 每收到一个 ACK,cwnd += 1 MSS → cwnd 成指数级增长(1, 2, 4, 8, 16…)

这样能迅速找到网络的“拥塞临界点”。

当 cwnd 达到某个阈值 ssthresh(慢启动阈值) 时,进入下一个阶段。

4.2 拥塞避免(Congestion Avoidance)

  • 当 cwnd ≥ ssthresh 时,不再指数增长,而是线性增长(每个 RTT 增加 1 MSS)。
  • 目的是逐步试探网络负载能力,防止再次拥塞。

4.3 快重传(Fast Retransmit)

在正常情况下,TCP 通过超时重传(RTO)判断丢包。 但如果等超时再重传,效率太低。

于是:

  • 如果发送方收到连续 3 个相同的 ACK(即“冗余 ACK”), 它就认为某个分段丢失,立即重传该分段,而不必等超时。

4.4 快恢复(Fast Recovery)

配合快重传使用。

  • 当检测到丢包后:

    • ssthresh = cwnd / 2
    • cwnd = ssthresh
    • 然后进入拥塞避免阶段(线性增长)

这样避免每次都回到“慢启动”阶段,提高效率。

4.5 图解

  • 慢开始(Slow Start)、
  • 拥塞避免(Congestion Avoidance)、
  • 超时重传后的重启
  • 以及 快速重传 + 快速恢复 的阶段。

4.5.1 图像概述

横轴:传输轮次(Round Trip Times, RTT) 纵轴:拥塞窗口 cwnd(以报文段 MSS 为单位)

图展示了 TCP 发送方的 cwnd 随着传输过程的变化,反映了网络拥塞控制的核心思想:“循序渐进地探测网络能力,拥塞时迅速回退,防止网络崩溃。”

4.5.2 阶段 1:慢开始(Slow Start)

图中最左边,cwnd 从 1 开始(每次只发送一个段)。 随着每次成功收到 ACK,TCP 将 cwnd 加倍,即指数级增长:

传输轮次cwnd增长方式
11初始
22乘 2
34乘 2
48乘 2
516乘 2

在这个阶段,TCP 试探性地增加发送速率,以快速占满网络带宽。

这种快速增长称为“慢开始”,其实并不慢,而是相对于瞬间全速发送而言更“温和”地增长。

4.5.3 阶段 2:拥塞避免(Congestion Avoidance)

当 cwnd 达到一个阈值(通常称为 ssthresh,Slow Start Threshold)后, TCP 认为网络已经接近饱和,不再使用指数增长,而是改用线性增长:每经过一个往返时间(RTT),cwnd = cwnd + 1

这对应图中大约从第 5 轮开始,cwnd 逐渐缓慢上升(16 → 18 → 19 → 20 → 22 → 23 → 24)。 此时网络处于拥塞避免阶段,TCP 小心地探测带宽上限。

4.5.4 阶段 3:发生超时(Timeout)

当 cwnd 增长到一定程度(约第 12 次传输)时,突然出现 拥塞事件:

  • 可能是因为网络过载导致分组丢失;
  • 或者接收方 ACK 超时未返回。

此时 TCP 会判定网络出现拥塞,采取剧烈收缩策略:

操作含义
将 ssthresh 设为当前 cwnd 的一半例如 cwnd=24 → ssthresh=12
将 cwnd 重置为 1回到慢开始阶段

这对应图中第一次“断崖式下降”—— cwnd 从约 24 掉到 1。 此后又重新进入“慢开始”阶段。

4.5.5 阶段 4:第二次慢开始 + 拥塞避免

从第 13 轮开始,TCP 重新启动慢开始:

  • cwnd 从 1 开始;
  • 以指数方式增长到 ssthresh = 12;
  • 到达阈值后,又转为线性增长。

这正是图中第二次“上升曲线”:先陡升、再平缓。

4.5.6 阶段 5:快速重传 + 快速恢复

在第 21 轮附近,图中出现第二次“突然下降”,但这次并没有回到 1,而是掉到 8 左右,然后继续缓慢上升。

这说明:此次丢包不是超时引发,而是通过 快速重传(Fast Retransmit) 检测到的。

4.5.6.1 快速重传

当发送方连续收到 三个相同的 ACK(即三次重复确认) 时, TCP 判断某个报文段可能丢失(而不是所有数据都堵住),于是立即重传该段,而不必等超时。

4.5.6.2 快速恢复

进入快速重传后,TCP:

  • 将 ssthresh 设为当前 cwnd 的一半;
  • 将 cwnd 暂时降为 ssthresh + 3;
  • 随后进入拥塞避免阶段(线性增长)。

因此在图中:

  • cwnd 从 16 → 8(下降一半);
  • 然后缓慢上升(线性增加); 这正是快速恢复阶段的典型特征。

4.5.7 整体流程总结

阶段特征增长方式触发条件下一步
慢开始cwnd 指数增长cwnd ×2cwnd ≥ ssthresh→ 拥塞避免
拥塞避免cwnd 线性增长cwnd +1分组丢失或超时→ 拥塞处理
拥塞处理(超时)cwnd 重置为 1重新慢开始超时→ 慢开始
快速重传 + 快速恢复cwnd 减半线性增长三次重复 ACK→ 拥塞避免

4.5.8 从图中读出的网络意义

从整个 cwnd 曲线可以看到:

  • TCP 的核心是“探测 + 回退”;
  • 它不会一次性冲满带宽,而是试探性地增加;
  • 一旦检测到网络拥塞,就立即收缩发送速率;
  • 随后重新探测带宽上限;
  • 整个过程不断循环,使得网络稳定在“临界负载附近”。

这就是 TCP 拥塞控制的精髓所在:“逐步增加速度,丢包立刻刹车”。

5. 流量控制 vs 拥塞控制

对比维度流量控制拥塞控制
控制范围发送方与接收方之间整个网络
控制目标防止接收方被“淹没”防止网络被“塞爆”
控制依据接收方缓冲区大小(rwnd)网络状态(丢包、延迟、ACK)
核心变量rwnd(接收窗口)cwnd(拥塞窗口)
调整逻辑接收方告诉发送方“我还能接多少”发送方根据丢包/ACK动态调整
共同点都是通过“控制发送速率”来实现可靠高效传输 
  • 流量控制:关注“接收方”,防止“接不过来”;
  • 拥塞控制:关注“网络”,防止“传不过去”;
  • 二者配合:保证 TCP 既稳又快。

当理解了这两种机制的本质,就能更好地理解 TCP 的行为—— 为什么下载刚开始很慢(慢启动), 为什么丢包后速度突然下降(拥塞控制), 以及为什么某些连接即使双方性能都很强,仍然跑不满(受网络或窗口限制)。

6. 缩写对照表

英文全称英文缩写中文全称
Transmission Control ProtocolTCP传输控制协议
Flow Control—流量控制
Congestion Control—拥塞控制
Receive Windowrwnd接收窗口
Congestion Windowcwnd拥塞窗口
Sliding Window—滑动窗口
AcknowledgmentACK确认报文(确认应答)
Maximum Segment SizeMSS最大报文段长度
Slow Start—慢开始(慢启动)
Slow Start Thresholdssthresh慢开始阈值
Congestion Avoidance—拥塞避免
Fast Retransmit—快速重传
Fast Recovery—快速恢复
Round Trip TimeRTT往返时延
Timeout RetransmissionRTO超时重传时间(重传超时)
Buffer Overflow—缓冲区溢出
Zero Window ProbeZWP零窗口探测
Receive Buffer—接收缓冲区
Sender / Receiver—发送方 / 接收方
Transmission Round—传输轮次
Duplicate AcknowledgmentDuplicate ACK重复确认(冗余 ACK)
Bandwidth—带宽
Network Congestion—网络拥塞
Data Segment—数据报文段
Reliable Transmission—可靠传输
Round Trip TimesRTTs多次往返时延(复数形式)
Timeout Event—超时事件
Congestion Event—拥塞事件

7. References

  1. 🔗你管这破玩意叫TCP?
This post is licensed under CC BY 4.0 by the author.