Skip to content

模型Model

TCP连接建立、半关闭与终止

TCP connection lifecycle · Three-way handshake · Half-close · TIME-WAIT

用两端序号推演三次握手及单方向FIN,区分EOF、RST与业务完成,并解释旧连接数据隔离。

形式陈述 ​

TCP连接为两个端点维护独立的字节序号空间。通常用源IP、源端口、目的IP、目的端口四元组标识当前连接,再用初始序号、状态及旧段寿命等规则区别四元组的不同连接实例。相同四元组重新连上,不等于继续旧连接的业务历史。

在通常主动打开/被动监听的状态机中,客户端发送SYN后进入SYN-SENT;服务端从LISTEN收到合格SYN,发送SYN+ACK并进入SYN-RECEIVED;双方根据后续合格响应进入ESTABLISHED。每个SYN占一个序号,因此握手确认的不是“零字节所以序号不变”。同时打开、重传和异常报文还有更多分支,本页只推演通常路径。

正常发送方向结束由FIN标记。FIN排在已发数据之后,也占一个序号;只有缺口补齐并按序到达FIN,接收方才得到该方向的有序结束。两个方向独立关闭,一端不再发送后,另一端仍可发送数据。这称半关闭。它与半开连接不同:后者通常指一端遗失状态而另一端仍认为连接存在。

应用API须单独核对。POSIX的shutdown(SHUT_WR)关闭后续发送方向,保留接收能力;close释放描述符及其引用,不是跨平台通用的“只发FIN且继续读”指令。正常FIN与异常RST也不同:RST中止连接,未交付数据可能丢弃,不能把它当成完整消息结束符。

直觉

握手让双方确认当前连接使用哪套序号。关闭则像说“我的这封信写完了”,并不要求对方也同时停止回信。请求发送完再半关闭,仍可以等服务端算出响应。

结束标记保证的是字节方向结束,而非业务协议成功。若预期10字节响应却只收到4字节就FIN,这是一条正常关闭的传输方向,却是一条截断的应用消息。

例子与边界

从握手到单向结束 ​

客户端初始序号100,服务端初始序号700。三步为:C→S:SYN,SEQ=100;S→C:SYN+ACK,SEQ=700,ACK=101;C→S:ACK,SEQ=101,ACK=701。随后C的首数据是101,S的首数据是701。

C发送3字节请求,占[101,104),然后shutdown发送方向,FIN占104。S收到连续数据与FIN后回复ACK=105,进入CLOSE-WAIT,应用在读完请求后才观察该方向EOF。S仍可发送2字节响应,占[701,703);自己的发送方向结束时FIN占703。C确认到704;C此前的FIN已获确认时,通常经FIN-WAIT-2进入TIME-WAIT。S收到对自己FIN的确认后从LAST-ACK结束。

如果C的FIN先于请求中缺失的字节到达,不能把EOF越过缺口提前交给应用。相反,如果双方都先等待对方EOF才肯发送任何结束标记,就可能应用级互等;TCP全双工能力不会替两边设计交互顺序。

为什么不能立即把旧四元组当成全新历史 ​

TIME-WAIT的规范基本时长为2×MSL,MSL是最大报文生存期模型参数。它给旧段消退及最后确认丢失后的FIN重传留下处理窗口;具体实现及安全复用扩展另有条件。不能把“2×MSL”直接固定为所有操作系统都相同的秒数。

新连接的握手只建立新字节序号状态。若旧连接上的请求已经执行而回复丢失,新连接并不会自动继承请求结果或去重记录。客户端仍需业务结果协议判断是否可重试。

推论与应用

对长度大于0的stream接收调用,成功返回0可表示对端有序关闭且可读字节已耗尽;不能推广到请求长度本来为0的调用或零长度UDP数据报。应用应把完整帧、帧中EOF、正常无剩余EOF和错误分别处理。

握手成功不认证现实身份,也不保证后续一直可达。一个已建立但长期沉默的连接,可能空闲、拥塞或断路;业务deadline仍需由应用自己的合同承担。

参考资料
  • RFC 9293,2022,§§3.5–3.6.1,建立、FIN、RST、half-close与TIME-WAIT;§3.4,SYN/FIN序号。
  • POSIX.1-2024,shutdown、recv,发送方向关闭与有序接收终止;2026-10-08实读。
关系图谱7 个相邻概念 · 1 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组