ArcLibrary

TCP 流量控制与滑动窗口

怎么让「发得快的人」不把「收得慢的人」打爆。

TCP滑动窗口流量控制
核心 · Key Idea

一句话:TCP 接收方在每个 ACK 里告诉发送方「我现在还能接 N 字节」(接收窗口 rwnd)。发送方永远不超过 rwnd,从机制上避免接收端缓冲被打爆。

是什么#

发送窗口 = min(rwnd, cwnd)
        ↑              ↑
    对端告知接收能力   本端估计网络能力

发送方维护一个滑动窗口:已确认 / 已发未确认 / 可发未发 / 暂不可发四段。每次收到 ACK 把窗口右移。

打个比方#

打个比方 · Analogy

你给朋友家送水。朋友说「我家还能放 5 桶」(rwnd=5),你就最多送 5 桶;他喝掉 3 桶后告诉你「还能放 3 桶」(rwnd=3),你接着送。你绝不会送到放不下的程度

关键概念#

rwndReceive Window
对端通告的剩余接收缓冲区大小。
Window Scaling窗口缩放
rwnd 字段只有 16 位(最大 64KB),靠 TCP option 把它放大到最大 1GB。
Zero Window零窗口
对端 rwnd=0,发送方暂停。后续靠 Window Probe 探测恢复。
Nagle 算法Nagle
把多个小段合并发送,减小开销。代价是**额外延迟**。
Delayed ACK延迟确认
接收方不立即 ACK,凑一段再回。和 Nagle 配对会导致**死等**,是经典坑。

怎么工作#

接收方应用读得越慢,rwnd 越快变小,发送方就跟着减速。

实操要点#

  • 现代 OS 默认开 Window Scaling,跨洋长肥管道(高 BDP)必备。

  • 服务器接收缓冲调优

    sysctl -w net.core.rmem_max=16777216
    sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216'

    缓冲不够 = rwnd 小 = 拉不满带宽。

  • 应用 read 不勤:会让 rwnd 长时间为 0,发送方挂起 —— 看起来像「丢包」其实是「收得慢」。

  • 关 Nagle(TCP_NODELAY:对实时性敏感的小包(IM、游戏、SSH 交互)必须关。

  • 不要混淆 rwnd 与 cwnd:rwnd 是接收能力,cwnd 是网络能力,发送方取较小值。

易混点#

rwnd 满了
**接收方应用读太慢**。
解:调大缓冲 / 让应用更快读。
cwnd 减半
**网络上有丢包**。
解:换更稳定的链路 / 拥塞算法(BBR)。

延伸阅读#