计算机网络学习站

kp-018 · 04-传输层

TCP 连接管理:三次握手与四次挥手

核心 约 35 分钟 TCP三次握手四次挥手TIME_WAIT
我的进度:

注:本文基于模型知识整理,建议结合权威教材与 RFC 原文核对细节。

一句话定义

TCP(Transmission Control Protocol,传输控制协议)以三次握手建立连接、四次挥手释放连接,在不可靠的 IP 之上构造一条有状态的、全双工的字节流通道。

为什么重要

连接是 TCP 一切可靠机制的载体:初始序号同步、窗口协商都发生在握手阶段;而断连处理不当(尤其是 TIME_WAIT 堆积)正是线上「端口耗尽」「连接异常」类问题的直接来源。吃透每个握手挥手报文的语义,是排查连接拒绝、连接重置类故障的基本功。

前置知识

建议先读 kp-017《传输层总览与 UDP》,理解端口、四元组与传输层定位;本篇反复出现的序号机制将在 kp-019 中系统展开。

核心概念

  • TCP 五个基本特征:面向连接(通信前先建立)、字节流(byte stream,不保留报文边界)、全双工(双向同时收发)、点对点(一条连接仅两个端点,不广播不组播)、有状态(双方维护序号与窗口等状态)。
  • 序列号(sequence number, seq):本报文所载数据第一个字节在字节流中的编号;确认号(acknowledgment number, ack):期望对方发送的下一个字节号,隐含「此前字节全部收妥」的累积语义。
  • ISN(Initial Sequence Number,初始序号):每个方向随机生成;握手的核心目的就是双方互换并确认各自的 ISN。随机化的动机是安全——防止攻击者依据上一个连接的序号规律预测并注入伪造报文。
  • SYN 与 FIN 各消耗一个序号,这是它们的确认语义(ack = ISN + 1)可靠成立的前提。

图示

状态机主线(箭头上为触发事件与动作):

  主动打开                            被动打开
CLOSED ──发SYN──> SYN_SENT ────┐    ┌──── LISTEN
                   │收SYN+ACK发ACK  │收SYN发SYN+ACK
                   ▼               │    ▼
              ESTABLISHED <────────┴─ SYN_RCVD

  主动关闭                                被动关闭
ESTABLISHED ─发FIN→ FIN_WAIT_1            ESTABLISHED ─收FIN发ACK→ CLOSE_WAIT
                │收ACK                        │数据发完后发FIN
                ▼                             ▼
           FIN_WAIT_2 ────收FIN发ACK────→ TIME_WAIT ←───收ACK─── LAST_ACK
                                  等 2MSL
                                    ▼
                                  CLOSED
(CLOSING:双方同时发 FIN 时经过的中间态,收 ACK 后进入 TIME_WAIT)

原理与机制

三次握手:客户端发 SYN(seq=x)进入 SYN_SENT;服务端回 SYN+ACK(seq=y, ack=x+1)进入 SYN_RCVD;客户端回 ACK(ack=y+1),双方进入 ESTABLISHED,第三次握手可捎带数据。为什么两次不行?设想一个在网络中徘徊很久的旧连接 SYN 迟到到达:两次握手下服务端一旦回复就单方面进入连接态、分配缓冲区等待数据,而客户端根本不认这个连接——半开连接悬挂、资源白白占用;且两次握手无法让双方都确认对方的 ISN,序号没同步好,后续字节流必然错乱。第三次 ACK 让「双方都确认了对方的初始序号」形成闭环,对不认识的旧 SYN,客户端也会以 RST 拒绝。

四次挥手:主动方(设为客户端)发 FIN 进入 FIN_WAIT_1;服务端回 ACK 进入 CLOSE_WAIT,客户端进入 FIN_WAIT_2——此时连接处于半关闭(half-close):客户端不再发送但还能接收,服务端可把剩余数据发完;数据发完后服务端再发 FIN 进入 LAST_ACK;客户端回 ACK 进入 TIME_WAIT,服务端收到后关闭。ACK 与 FIN 分开发送,正是因为中间还隔着「把数据发完」这一步。

TIME_WAIT 必须等 2MSL(Maximum Segment Lifetime,报文最大生存时间):其一,最后的 ACK 若丢失,服务端会重传 FIN,只有主动方仍停留在 TIME_WAIT 才能补发 ACK,否则回 RST 令对端异常关闭;其二,等足 2MSL 让本连接的旧报文在网络中自然消亡,不致污染随后复用相同四元组的新连接。

RST 的典型场景:连接到不存在的端口、进程异常退出后内核强制重置、收到不合法报文。SYN Flood 用伪造源地址的海量 SYN 耗尽半连接队列;SYN Cookie 的思想是把连接状态编码进序号返回,收到合法 ACK 才分配资源,使服务端无需为半开连接保存状态。

实例分析

线上高频问题「大量 TIME_WAIT」:本机作为客户端高频短连接访问下游,每次主动关闭留下一个 TIME_WAIT,Linux 默认驻留 60 秒并占用本地端口,高峰期源端口耗尽、新连接建不起来。处置思路(细节见 kp-021):长连接化、连接池、开启 tcp_tw_reuse。另一个日常现象:curl 一个无人监听的端口立即得到 Connection refused——那是服务端内核回了 RST,这也是最快的端口探活方式。

常见误区

一,「三次握手是为了确认链路双向通」:这只是必要副产品,本质是交换并确认 ISN 并抵御旧连接报文;两次并非测不通链路,而是防不住历史 SYN、同步不好序号。二,「TIME_WAIT 出现在服务端就是异常」:只有主动关闭方才有 TIME_WAIT,出现在哪侧与谁是服务器无关。三,「进程崩溃就发 RST」:进程正常退出时内核通常完成四次挥手;主机宕机或网络中断形成的「死连接」要靠保活或应用心跳发现。四,把 SO_LINGER 置 0 强制 RST 关闭当作「更快的关闭」:代价是未发数据被丢弃、对端收到连接被重置的错误。

自测题

  1. 第三次握手的 ACK 丢失后会发生什么?

答案要点: 服务端停在 SYN_RCVD 并重传 SYN+ACK;客户端已进入 ESTABLISHED,收到重传后补发 ACK;重传耗尽则服务端放弃,后续客户端数据到达也能触发建连完成。

  1. 四次挥手为什么通常不能合并为三次?

答案要点: 被动方收到 FIN 时可能还有数据未发完,须先回 ACK 进入 CLOSE_WAIT,把数据发完再发自己的 FIN;两个报文语义与时序不同,故分开(无数据可发时可合并)。

  1. TIME_WAIT 为什么要等 2MSL?

答案要点: 保证最后的 ACK 丢失后能应答对端重传的 FIN,避免对端异常关闭;并让本连接旧报文自然消亡,防止污染复用四元组的新连接。

  1. 服务器出现大量 TIME_WAIT 说明什么、如何处理?

答案要点: 本机作为主动关闭方在高频短连接;处理思路是长连接化与连接池、端口复用(SO_REUSEADDR、tcp_tw_reuse),先测量定位再动配置。

  1. SYN Flood 攻击与 SYN Cookie 各利用或防御了握手的什么环节?

答案要点: 攻击利用半开连接需占服务端资源:伪造源地址发 SYN 不回 ACK,耗尽半连接队列;SYN Cookie 不保存状态,把状态编码进初始序号,收到合法 ACK 才真正分配资源。

延伸阅读

  • RFC 9293《Transmission Control Protocol (TCP)》连接建立与终止章节
  • W. Richard Stevens《TCP/IP 详解 卷 1:协议》(第 2 版)第 13 章
  • 谢希仁《计算机网络》(第 8 版)TCP 连接管理小节