高级 #network#tcp#congestion

TCP 流量控制与拥塞控制

流量控制(Flow Control)防止发送方太快淹没接收方——用滑动窗口调节。拥塞控制(Congestion Control)防止网络中间路由器被撑爆——用慢启动和拥塞避免

🚦 两个”堵车”的问题

TCP 要解决两个完全不同的”太快”问题:

问题 1:接收方来不及收(流量控制) 你说话太快——对方听不过来,记不住。你要慢点说。

问题 2:网络中间节点被撑爆(拥塞控制) 你说的话太多了——中间的”传话人”(Wi-Fi、路由器)处理不过来,排队太长,丢包了。

🏪 类比:食堂打饭

流量控制 = 你(服务器)往窗口端菜——窗口只有 5 个位置,端太快放不下,你得等窗口空出位置再端。

拥塞控制 = 食堂排队太长了——不是因为窗口慢,而是食堂大门只能同时进 10 个人(网络带宽有限)。你不能一次让 100 个人挤进去(发大量包)。


📏 流量控制——滑动窗口

流量控制(Flow Control) 防止”发送方太快,接收方来不及收”。

TCP 头部有一个 Window Size(窗口大小) 字段——接收方用它告诉发送方”我还能收多少字节”。

发送方                      接收方
  │                          │
  │──── 数据 1-1000 ──────→ │
  │──── 数据 1001-2000 ───→ │  接收方缓冲区满
  │──── 数据 2001-3000 ───→ │  处理不过来了!
  │                          │
  │←─ ACK, Win=0 ──────────│  "别发了,我满了!"
  │                          │  (发送方停止发送)
  │                          │  应用程序读取数据,腾出空间
  │←─ ACK, Win=5000 ───────│  "好了,继续发"
  │──── 数据 3001-4000 ───→ │

关键Win=0 告诉发送方”暂停”——直到接收方发出 Win>0 的确认才继续。这保证了接收方不会被淹没。


🚗 拥塞控制——慢启动 + 拥塞避免

拥塞控制(Congestion Control) 防止”发太快,网络撑不住”——中间路由器缓存满了,开始丢包。

① 慢启动(Slow Start)

刚开始发送时——不确定网络带宽,慢慢试探:

第 1 轮:发 1 个包 → 收到 ACK → 翻倍
第 2 轮:发 2 个包 → 收到 ACK → 翻倍
第 3 轮:发 4 个包 → 收到 ACK → 翻倍
第 4 轮:发 8 个包 → 收到 ACK → 翻倍
...

以指数速度增长——直到:
a) 达到阈值(ssthresh)→ 切换为拥塞避免
b) 发生丢包 → 认为网络拥塞 → 大幅降低发送速率

② 拥塞避免(Congestion Avoidance)

超过阈值后——不再翻倍,改为"每个 RTT(往返时间)加 1":

线性增长——缓慢探测网络极限

如果发生丢包(拥塞信号)→ 将阈值降为当前速率的一半
→ 重新从慢启动开始
发送速率

  │  ╱╲      ╱╲                    ╱╲
  │ ╱  ╲    ╱  ╲   丢包!         ╱  ╲   丢包!
  │╱    ╲  ╱    ╲────────╱  ╲──
  │       ╲╱             ╲╱
  │     慢启动          拥塞避免     慢启动
  └──────────────────────────────────────→ 时间

📊 TCP 拥塞控制的实际表现

场景TCP 行为
刚开始传输慢启动——从 1 开始指数增长
网络良好线性增长(拥塞避免)——探测上限
出现丢包认为网络拥塞——速率减半
长时间空闲重置拥塞窗口——重新慢启动
# Linux 查看当前 TCP 拥塞控制算法
$ sysctl net.ipv4.tcp_congestion_control
net.ipv4.tcp_congestion_control = cubic

# 常见算法:cubic(默认)、bbr(Google 开发,高吞吐)、reno(经典)

📝 小结

概念一句话
流量控制防止发送方淹没接收方——接收方告诉发送方”我的缓冲区还剩多少”
滑动窗口接收方通过 TCP 头部的 Window Size 控制发送速率
拥塞控制防止发送方撑爆网络——检测丢包后减速
慢启动开始时指数增长试探网络——直到发生丢包或达到阈值
拥塞避免超过阈值后线性增长——缓慢探测网络上限
BBRGoogle 的新算法——不靠丢包判断拥塞,更高效