摘要

  • TCP 将一条连接称为半开放,是因为一端丢失或删除了状态,而另一端并不知情。
  • 仍处于 ESTABLISHED 的一端发送数据时,已无状态的一端会返回 RST,旧连接随之中止。
  • 重启后发送的新 SYN 可能遇到对端保留的旧连接状态;不相容的 ACK 会促使发起方发送 RST。
  • RST 不会恢复数据或重建旧连接,而是删除过时状态,使新的握手能够开始。

一条连接,两份记忆

TCP 的连接状态分布在两个端点。双方分别保存序列号、确认号、窗口以及状态机位置。只有双方保存的连接状态仍然相互兼容时,应用看到的连接才成立。

RFC 793 和 RFC 9293 将这种情况定义为半开放:一端在另一端不知情时关闭或中止连接,或者故障、重启导致记忆丢失,使双方失去同步。这不同于正常的半关闭。FIN 有意关闭一个方向,同时保留另一个方向;半开放则是意外的状态分裂。

仍记得连接的一端先发送

假设 B 仍认为连接已同步并发送数据。A 已重启,处于 CLOSED,没有匹配的连接控制块。A 会把该报文视为不属于任何连接,并返回 RST。B 接收后中止自己保留的旧连接。

RST 不会告诉 B 故障前哪些数据已经处理,也不会说明应用事务是否完成。它只表明 A 无法继续参与 B 所保留的连接状态。

被遗忘的一端重新开始

A 也可能在重启后发送新的 SYN。B 仍保留旧连接,因此发现该 SYN 不在旧连接状态对应的接收窗口内,于是返回一个 ACK,指出它期待的序列号。A 尚未同步,发现这个 ACK 并未确认自己新尝试发送的内容,便发送 RST。B 删除旧状态,A 随后可以继续普通的三次握手。

协议不会合并互不相容的状态,而是终止已经无法共享的旧状态。

传输层的边界

RST 只能明确并清除传输层冲突,不能恢复丢失的字节、认证状态或应用事务。重试、检查点和幂等性属于上层。这里的例子也不等同于 FIN 半关闭、必需的 keepalive,或 RFC 5961 的 challenge-ACK 加固机制。

来源