零窗口探测是TCP为解决接收方窗口为0时发送方无限等待问题而设计的保活机制:发送方在persist timer超时后周期性发送1字节伪数据探测段,逼迫接收方返回最新窗口值,若持续无响应达tcp_retries2次则断连。

零窗口探测(Zero Window Probe)是什么
当接收方 TCP 缓冲区已满,它会通过 ACK 报文将窗口字段置为 0,通知发送方“暂时别发数据”。但这个“暂时”有多久?如果接收方一直不发新 ACK(比如应用进程卡住、未及时读取 socket 缓冲区),发送方就会陷入无限等待——既不能发数据,又不知道对方是否还活着。零窗口探测就是为解决这个问题而设计的保活机制:发送方在窗口为 0 后,周期性地发出一个携带 1 字节伪数据的探测段(通常为序号为 snd.nxt-1 的重复报文),逼迫接收方响应当前真实的接收窗口大小。
零窗口探测的触发条件与时间规律
零窗口探测不是立即启动的,它依赖两个关键状态:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 发送方本地维护的 persist timer(坚持定时器)被激活,该定时器在收到窗口为 0 的 ACK 后启动;
- 定时器超时后,发送方发出第一个 probe;若仍收到 window=0 的 ACK,则重置 persist timer 并按指数退避策略延长下次探测间隔(常见实现:初始 500ms → 1s → 2s → 4s … 直到上限,如 60s)。
- Linux 内核中,persist timer 的初始值由 tcp_retries2 和底层 rto(重传超时)共同影响,但实际探测间隔主要受 tcp_rmem 缓冲区压力、net.ipv4.tcp_slow_start_after_idle 等参数间接调控;默认行为下,首次探测约在窗口关闭后 300–500ms 发出。
接收方如何响应零窗口探测
接收方收到 probe 后,不管窗口是否仍为 0,都必须回复一个纯 ACK(不含数据),其中携带当前最新的 advertised window 值。这是强制性 TCP 规范要求:
- 若应用已读取部分数据、缓冲区有空闲,窗口恢复为正值,ACK 中 window > 0,发送方随即恢复正常数据传输;
- 若缓冲区依然满,window 仍为 0,发送方继续按退避节奏发 probe;
- 若接收方主机崩溃或连接中断,probe 将得不到任何响应,persist timer 持续超时重试,直到达到内核设定的探测失败上限(由 tcp_retries2 控制,默认通常为 15 次),最终连接被内核主动关闭(状态转为 FIN_WAIT_1 或直接 abort)。
调试与观察零窗口探测的实际方法
可通过以下方式在 Linux 系统中确认零窗口探测行为:
- 用 tcpdump 抓包,过滤 tcp[tcpflags] & (tcp-rst|tcp-syn) == 0 and tcp len == 0,再结合窗口字段为 0 的 ACK 和紧随其后的小序号重复 ACK,即可识别 probe 及其响应;
- 查看 socket 状态:ss -i 输出中的 pmtu、rcv_space、rwnd 等字段可辅助判断接收窗口是否长期为 0;
- 启用内核网络调试:设置 net.ipv4.tcp_debug = 1(需 CONFIG_TCP_DEBUG=y),配合 dmesg 查看零窗口相关日志(生产环境慎用);
- 模拟场景:用 nc -l 8080 启服务端,客户端用 Python socket 发送数据后暂停 recv(),再用 ss -i 观察 rwnd 趋势和重传队列变化。

















