窗口值为什么要换算
TCP 头里的接收窗口是 16 位字段,理论上限 65535 字节,在高带宽长延迟链路上远远不够用。为此握手阶段会协商窗口缩放因子,之后报文里的窗口值要乘以 2 的缩放次幂才是真实可接收字节数。Wireshark 默认显示已经还原后的计算值,而原始 16 位值另有一个字段;核算吞吐上限时用错字段会得出偏小一个数量级的结论。
基本信息
| 原始字段 | tcp.window_size_value,报文头里的 16 位数值 |
|---|---|
| 计算字段 | tcp.window_size,已按缩放因子还原的实际窗口 |
| 缩放因子 | 握手选项中的窗口缩放位移值,字段为 tcp.options.wscale.shift |
| 换算公式 | 实际窗口 = 原始值 × 2 的位移次幂 |
| 交叉验证 | 用 ss -ti 的窗口相关字段对照,字段名随 iproute2 版本不同 |
| 边界情况 | 窗口为 0 时不受缩放影响,零乘任何数仍为零 |
典型使用场景
- 吞吐核算:按窗口与往返时间估算单连接吞吐上限,解释为什么大带宽链路上反而跑不快
- 背压定位:接收窗口持续变小或归零,说明消费端处理不过来,而不是网络丢包
- 两头对账:把抓包换算出的窗口与主机侧套接字信息对照,确认两端读的是同一口径
- 协议分析教学:用真实抓包演示 16 位窗口为什么必须配合缩放才能支撑现代带宽
- 性能回归:改动内核参数前后各抓一段,比较窗口变化趋势
查看与换算
查看与换算
# 握手阶段协商出的缩放位移(两端各发一次)
tshark -r a.pcap -Y 'tcp.options.wscale' -T fields -e ip.src -e tcp.options.wscale.shift
tshark -r a.pcap -Y 'tcp.stream == 7' -T fields -e frame.number -e tcp.window_size_value -e tcp.window_size
# 主机侧交叉验证(字段名随 iproute2 版本不同)
ss -ti dst 10.0.0.9
# 只看零窗窗口的帧
tshark -r a.pcap -Y 'tcp.analysis.zero_window' -T fields -e frame.number -e tcp.window_size字段与判读
| 字段 | 含义 | 判读提示 |
|---|---|---|
| tcp.window_size_value | 报文里的原始 16 位窗口 | 超过 65535 一定不是原始值 |
| tcp.window_size | 按缩放还原后的窗口 | 核算吞吐时用这个 |
| wscale 位移 | 握手协商的缩放次幂 | 缺失时窗口无法放大 |
| 窗口骤降 | 接收方缓冲区被占满 | 先查消费端处理速度再看网络 |
| 窗口归零 | 接收方暂时无法接收 | 常伴随发送方零窗探测 |
| 两侧窗口差异大 | 一端读原始值一端读还原值 | 先统一口径再比较 |
窗口为 0 的判断不受缩放影响,可以直接按字段值判定;有争议的只有非零窗口的换算,此时必须回到握手阶段确认位移值。
不同工具对窗口的口径不一致:抓包工具显示还原值,系统工具可能显示套接字层的可用缓冲,两者混用会得出矛盾结论,出结论前先明确各自的定义。