TCP零窗口是接收方通告window=0,强制发送方暂停传输的流量控制机制,由接收缓冲区满或处理能力不足引发,需通过tcpdump捕获win 0报文定位接收端瓶颈。

直接用 tcpdump 捕获并筛选 window size = 0 的 TCP 报文,是排查“零窗口卡顿”最有效的一线手段。因为零窗口(Zero Window)意味着接收方已无缓冲空间,主动通告 window=0,发送方必须暂停发包——这是 TCP 流控机制的明确信号,不是丢包或延迟,而是接收侧资源瓶颈。
确认零窗口报文特征
TCP 头部中 window 字段占 2 字节,值为 0 即表示零窗口通告。tcpdump 默认输出中会显示 win 0(例如:Flags [.],ack 12345,win 0,length 0)。注意:
- 该字段出现在 ACK 报文中(通常不含 payload),由接收方发出;
- 仅看
win 0不够,需结合方向判断:若服务端持续发win 0,说明其应用未及时读取 socket 接收缓冲区; - 不要混淆
win 0和urg、push等标志位——它们无关流控。
抓取 win=0 的关键命令
推荐组合过滤,兼顾准确性和可读性:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 捕获所有接口上 window=0 的 TCP ACK 报文(最常用):
sudo tcpdump -i any 'tcp[tcpflags] & tcp-ack != 0 and tcp[14:2] == 0' -nn -vv -s 0 - 限定只看服务端(如 192.168.1.200)发出的零窗口通告:
sudo tcpdump -i eth0 'src host 192.168.1.200 and tcp[tcpflags] & tcp-ack != 0 and tcp[14:2] == 0' -nn -vv - 保存为 pcap 供后续分析(避免终端刷屏丢失):
sudo tcpdump -i any 'tcp[tcpflags] & tcp-ack != 0 and tcp[14:2] == 0' -w zero_win.pcap -C 10 -W 3(单文件≤10MB,最多轮转3个)
说明:tcp[14:2] 表示从 TCP 头第 14 字节起取 2 字节 —— 正是 window 字段位置(固定偏移,不依赖选项);-nn 防止 DNS/端口反解影响判断;-vv 显示完整 TCP 头信息,含 window、seq、ack、flags 等。
区分真零窗口与假象
有些 win 0 是瞬时、无害的,需结合上下文判断是否构成卡顿:
- 连续多个 win=0(尤其间隔
- 伴随大量 retransmission 或 dup ack:说明发送方已因零窗口停发,但超时后重传——此时连接已僵死;
-
仅在连接建立初期出现 win=0:可能是应用尚未调用
recv(),属正常启动延迟; - 抓包位置在客户端侧看到服务端发 win=0:问题在服务端;若在服务端侧看到客户端发 win=0,则问题在客户端。
辅助验证与定位
抓到零窗口后,不能只看包,要联动系统指标:
- 查服务端 socket 缓冲区使用:
ss -i src :8080 | grep -A2 "rcv_space\|rcv_ssthresh"(观察rcv_wscale和实际rcv_space是否长期为 0) - 查对应进程堆栈:
sudo gdb -p $(pgrep -f 'your_app') -ex 'thread apply all bt' -ex quit 2>/dev/null | grep -A5 'recv\|read\|epoll'(看是否卡在系统调用) - 用
tshark -r zero_win.pcap -Y 'tcp.window_size == 0' -T fields -e ip.src -e tcp.srcport -e ip.dst -e tcp.dstport快速统计哪些连接频繁触发零窗口。

















