核心 · 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)。
解:换更稳定的链路 / 拥塞算法(BBR)。