摘要
- 零窗口探测让接收方重新报告当前窗口,避免一次丢失的纯 ACK 把连接永远困在旧状态里。
- TCP 负责保留恢复传输的可能;是否继续占用资源、等待多久,仍由操作系统和应用决定。
一条 TCP 连接可能在没有断线、没有崩溃、双方也都遵守协议的情况下停住。接收端应用暂时不再读取数据,缓冲区逐渐填满,于是 TCP 把接收窗口通告为零。发送方服从流量控制,不再正常发送。稍后,应用腾出了空间,接收端便用一个 ACK 宣布窗口重新扩大。
问题出在这份新通知可能只有一份。纯 ACK 本身并不获得可靠重传的保证。它一旦在网络里丢失,接收方以为自己已经归还了发送额度,发送方却仍保存着“窗口为零”的旧认识。接收方等新数据,发送方等新额度,谁都没有必然触发下一条消息的理由。流量控制没有出错,错的是两端掌握了不同版本的状态。
TCP 的零窗口探测,就是为这种知识差设计的。即使对方通告的窗口仍为零,发送方也会隔一段时间发送或重传少量数据,使接收方必须答复。回复中包含下一个期望序列号和当下的窗口。窗口若已打开,发送方便重新得到这个事实;窗口若仍为零,它也只是获得一次更新后的确认,不能借探测之名越过接收方设定的边界。
这套结构在 1981 年的 RFC 793 中已经出现。原始 TCP 规范要求:窗口为零时,发送方仍应定期重传;接收方收到报文后,仍要用 ACK 报告下一个期望序列号与当前窗口。规范给出的理由很窄,也很关键——只有这样,一方重新打开窗口时,另一方才能可靠地获知变化。早期文本中的具体时间建议后来演进了,但“迫使状态再次出现”的控制逻辑保留下来。
1989 年的 RFC 1122 把要求说得更明确:主机必须支持零窗口探测。它直接指出,如果没有探测,而那条负责重新打开窗口的 ACK 恰好丢失,连接就可能永久挂起。文件还建议在零窗口持续一个重传超时周期后发送第一次探测,后续探测间隔再按指数方式拉长。
先在一个 RTO 后询问,能较快修复一次偶然丢包;逐步放慢,则避免长时间暂停变成持续不断的打扰。这种节奏没有给发送方创造新的额度。探测只是在问:“你刚才告诉我的零,仍然是现在的状态吗?” 接收方仍掌握窗口,发送方仍必须服从。
RFC 1122 同时保留了一个容易被误读的条件:接收方可以无限期地关闭它所提供的窗口。只要它继续回应探测,发送方就必须允许连接保持打开,但应用自己的用户超时策略仍然有效。规范用打印机缺纸举例。打印程序暂停取走数据,可能只是因为一个协议之外、而且可以恢复的问题。TCP 看不到纸张,也不知道工作人员何时补充;仅凭窗口长时间为零就宣判连接死亡,会把外部暂停误当成传输故障。
发送方处在这种局面时,通常称为进入 persist condition,也就是持续状态。到了 2011 年,RFC 6429 专门澄清了这里的另一面:允许协议等待,并不等于要求机器无条件保留所有资源。对端可以一直通告零窗口,同时继续确认探测;发送端则可能长期占着发送队列中的数据、缓冲区与连接状态。大量连接如此停留时,服务器可能没有足够资源服务正常连接。
RFC 6429 没有把所有零窗口都定义成攻击,也没有为探测机制塞入一个统一的强制终止计时器。它划清了权力边界:TCP 不应仅因连接处于持续状态就自行关闭;但操作系统或应用仍可按照正常资源策略终止连接、回收内存。协议的耐心不是资源所有者的无限责任。
现行综合规范 RFC 9293 延续了这套安排。零窗口探测仍是必须支持的行为;接收方仍需回复其当前窗口和下一个期望序列号;第一次探测应在一个 RTO 之后发生,随后的间隔应指数增长。规范也继续承认资源管理的约束。被保留下来的不是“所有连接都要永远等待”,而是“只要决定保留连接,就必须让窗口状态仍有办法被重新取得”。
因此,探测获得的是传输层证据,而不是应用层结论。收到 ACK,说明对端 TCP 仍在报告序列空间和窗口;它不证明接收应用正在推进,也不承诺很快接收数据,更不能证明继续维持连接仍有业务价值。探测修复的是丢失的状态更新,不负责预测未来。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
