--- tags: [计算机网络, TCP, 状态机, 三次握手, 四次挥手] create time: 2026-05-18 01:30 --- # TCP 段结构与状态机 ## 概述 TCP(Transmission Control Protocol)是互联网最核心的可靠传输协议。理解其段结构和完整状态机,是排查线上网络问题的基本功。 ## TCP 首部格式(32-bit fields) ``` ┌─────────────┬─────────────┬───────────────────┐ │ Source Port │ Destination Port│ Sequence No │ │ 2 bytes │ 2 bytes │ 4 bytes │ ├─────────────┼───────────────┤ │ │ Ack No │ Data Offset | Reserved│ECN│ CWR│ ACK │ PSH │ RST │ SYN │ FIN │ │ 4 bytes │ 4bits │ 3 bits │ │ │ │ │ │ ├─────────────┴─────────────┴───────────────────┤ │ Window Size │ │ 2 bytes │ ├───────────────────┬───────────────────────────┤ │ Checksum │ Urgent Pointer │ │ 2 bytes │ 2 bytes │ ├───────────────────┴───────────────────────────┤ │ Options (variable) │ │ Max: 40 bytes │ └───────────────────────────────────────────────┘ Minimum header: 20 bytes Maximum header: 60 bytes (with options) ``` ### 关键字段详解 | 字段 | 大小 | 说明 | |------|------|------| | **Source/Dest Port** | 各 2B | 源端口和目的端口 | | **Sequence Number** | 4B | 本报文第一个字节的序号(32 bit,约 4GB) | | **Acknowledgment Number** | 4B | 期望收到的下一个字节序号(ACK=1 时有效) | | **Data Offset** | 4 bit | 首部长度,单位 4 bytes(最小 5 = 20B,最大 F = 60B) | | **Reserved** | 3 bit | 保留字段,必须为 0 | | **ECN** | 2 bit | ECN-Echo + CWR:显式拥塞通知 | | **URG** | 1 bit | 紧急指针有效 | | **ACK** | 1 bit | 确认号有效(除首次 SYN 外几乎所有包都设 ACK=1) | | **PSH** | 1 bit | 推送标志,告诉接收端立即提交应用层 | | **RST** | 1 bit | 复位连接(异常关闭) | | **SYN** | 1 bit | 同步序列号(建立连接) | | **FIN** | 1 bit | 结束标志(优雅关闭) | | **Window Size** | 2B | 接收窗口大小,流量控制基础 | | **Checksum** | 2B | 覆盖首部 + 数据的 CRC | | **Urgent Pointer** | 2B | URG=1 时偏移量,指示紧急数据位置 | ### 常用 TCP Options | Option | 大小 | 说明 | |--------|------|------| | NOP | 1B | No Operation,用于填充对齐 | | MSS | 4B | Maximum Segment Size,通常 1460(1500-MT-20IP) | | Window Scale | 4B | 扩大窗口因子(2^x倍,最大 14 = 16384 倍) | | SACK Perm / SACK | 可变 | Selective Acknowledgment,选择性确认 | | Timestamps | 10B | TSval + TSecr,RTT 测量和防回绕 | ## TCP 状态机——完整图 ```mermaid stateDiagram-v2 [*] --> CLOSED note right of CLOSED TCP 不活跃状态 只有监听套接字在此 end note CLOSED --> LISTEN: socket() + listen() LISTEN --> SYN_RCVD: 收到 SYN (server only) LISTEN --> ESTABLISHED: connect() + remote SYN-ACK (client side rare) note right of SYN_SENT client sent SYN waiting for SYN-ACK end note SYN_RCVD --> ESTABLISHED: 3-Way Handshake Complete SYN_SENT --> ESTABLISHED: Got SYN-ACK ESTABLISHED --> CLOSE_WAIT: Application calls close() ESTABLISHED --> FIN_WAIT_1: Remote sends FIN FIN_WAIT_1 --> FIN_WAIT_2: Local ACK received FIN_WAIT_1 --> CLOSING: Simultaneous close FIN_WAIT_2 --> TIME_WAIT: Remote FIN received CLOSING --> TIME_WAIT: Remote ACK received CLOSE_WAIT --> LAST_ACK: Local application close LAST_ACK --> CLOSED: Final ACK received TIME_WAIT --> CLOSED: 2 * MSL timeout note right of TIME_WAIT Must wait 2*MSL Ensures final ACK arrives Prevents old duplicate packets end note note right of CLOSE_WAIT Server side closing Application must call close() end note ``` ### 所有 11 种状态一览 | # | 状态 | 触发条件 | 谁处于? | |---|------|---------|---------| | 1 | CLOSED | 初始/终止 | 双方初始状态 | | 2 | LISTEN | `listen()` 系统调用 | 服务端 | | 3 | SYN_SENT | `connect()` 发出 SYN | 客户端 | | 4 | SYN_RCVD | 收到 SYN | 服务端 | | 5 | ESTABLISHED | 三次握手完成 | 双方 | | 6 | FIN_WAIT_1 | 本地调用 close() | 主动关闭方 | | 7 | FIN_WAIT_2 | FIN_WAIT_1 的 ACK 到达 | 主动关闭方 | | 8 | CLOSE_WAIT | 收到远程 FIN | **被动关闭方**(服务器!)| | 9 | CLOSING | 同时关闭 | 极少见 | | 10 | LAST_ACK | 本地发送最后一个 FIN | 被动关闭方 | | 11 | TIME_WAIT | 发送完最后一个 ACK | 主动关闭方 | > [!tip] 哪些状态是你最常看到的? > - **ESTABLISHED**: 正常工作 > - **TIME_WAIT**: 高频短连接的服务端(如 nginx、API 网关) > - **CLOSE_WAIT**: ⚠️ **应用 Bug!** 说明服务器收到了客户端的关闭请求但没调用 close() ### CLOSE_WAIT 堆积排查 ```bash # 查看 CLOSE_WAIT 数量 $ ss -tan state close-wait | wc -l 4521 # 是谁引起的?查进程 $ ss -tan state close-wait src :80 State Recv-Q Send-Q Local Address:Port Peer Address:Port Process CLOSE-WAIT 0 0 10.0.0.1:80 203.0.113.5:45678 app=nginx(1234) # 解决方案: 修复代码中未正确关闭的文件描述符/HTTP连接 ``` ## 关联笔记 - [[hhs/NETWORK/TCP三次握手与四次挥手]] — 详细解析握手/挥手过程 - [[hhs/NETWORK/TCP可靠传输机制]] — 序列号/确认号的深入讲解 - [[hhs/NETWORK/TCP拥塞控制]] — TCP 窗口的动态管理