RFC 9293
Transmission Control Protocol —— 2022 年把 RFC 793 及一串补丁收成现行 Internet Standard。首部、状态机、三次握手、四次关闭都在这里。
图 1:TCP 首部
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Rsrvd |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| [Options] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :
: Data :
: |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Note that one tick mark represents one bit position.
Figure 1: TCP Header Format[……节选 Source Port / Destination Port]
Sequence Number: 32 bits
The sequence number of the first data octet in this segment (except
when the SYN flag is set). If SYN is set, the sequence number is
the initial sequence number (ISN) and the first data octet is
ISN+1.
Acknowledgment Number: 32 bits
If the ACK control bit is set, this field contains the value of the
next sequence number the sender of the segment is expecting to
receive. Once a connection is established, this is always sent.
注解
无选项时 Data Offset=5,首部 20 字节。9293 把 CWR/ECE 画进主图(793 还没有),它们服务于 ECN,不是三次握手的角色。
序号按字节编号,不是按段。SYN 置位时 Seq=ISN,第一个数据字节是 ISN+1——也就是说 SYN 消耗一个序号。FIN 同样消耗一个。纯 ACK 不消耗序号,所以握手第三拍和紧随其后的数据可以共用同一个 Seq。
Ack 是累积确认:“我期望的下一个字节”。Ack=x 表示 x 之前都到了,不是“只确认了第 x 号”。
十一个状态的官方定义
A connection progresses through a series of states during its
lifetime. The states are: LISTEN, SYN-SENT, SYN-RECEIVED,
ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK,
TIME-WAIT, and the fictional state CLOSED. CLOSED is fictional
because it represents the state when there is no TCB, and therefore,
no connection. Briefly the meanings of the states are:
LISTEN - represents waiting for a connection request from any remote
TCP peer and port.
SYN-SENT - represents waiting for a matching connection request
after having sent a connection request.
SYN-RECEIVED - represents waiting for a confirming connection
request acknowledgment after having both received and sent a
connection request.
ESTABLISHED - represents an open connection, data received can be
delivered to the user. The normal state for the data transfer
phase of the connection.
FIN-WAIT-1 - represents waiting for a connection termination request
from the remote TCP peer, or an acknowledgment of the connection
termination request previously sent.
FIN-WAIT-2 - represents waiting for a connection termination request
from the remote TCP peer.
CLOSE-WAIT - represents waiting for a connection termination request
from the local user.
CLOSING - represents waiting for a connection termination request
acknowledgment from the remote TCP peer.
LAST-ACK - represents waiting for an acknowledgment of the
connection termination request previously sent to the remote TCP
peer (this termination request sent to the remote TCP peer already
included an acknowledgment of the termination request sent from
the remote TCP peer).
TIME-WAIT - represents waiting for enough time to pass to be sure
the remote TCP peer received the acknowledgment of its connection
termination request and to avoid new connections being impacted by
delayed segments from previous connections.
CLOSED - represents no connection state at all.
注解
CLOSED 是“没有 TCB”,不是一个真能待着的房间。LISTEN 是被动打开(服务器 listen);SYN-SENT 是主动打开(客户端 connect)。
ESTABLISHED 才允许把数据交给用户。握手第三拍到达之前,即便 SYN 段里夹了数据,也要先缓冲。
TIME-WAIT 等的是 2MSL:既给最后那个 ACK 一次重传窗口,又让本四元组的迟到报文在网上死掉,以免污染下一个相同四元组的连接。
TCP 连接状态图
NOTA BENE: This diagram is only a summary and must not be taken as
the total specification. Many details are not included.
+---------+ ---------\ active OPEN
| CLOSED | \ -----------
+---------+<---------\ \ create TCB
| ^ \ \ snd SYN
passive OPEN | | CLOSE \ \
------------ | | ---------- \ \
create TCB | | delete TCB \ \
V | \ \
rcv RST (note 1) +---------+ CLOSE | \
-------------------->| LISTEN | ---------- | |
/ +---------+ delete TCB | |
/ rcv SYN | | SEND | |
/ ----------- | | ------- | V
+--------+ snd SYN,ACK / \ snd SYN +--------+
| |<----------------- ------------------>| |
| SYN | rcv SYN | SYN |
| RCVD |<-----------------------------------------------| SENT |
| | snd SYN,ACK | |
| |------------------ -------------------| |
+--------+ rcv ACK of SYN \ / rcv SYN,ACK +--------+
| -------------- | | -----------
| x | | snd ACK
| V V
| CLOSE +---------+
| ------- | ESTAB |
| snd FIN +---------+
| CLOSE | | rcv FIN
V ------- | | -------
+---------+ snd FIN / \ snd ACK +---------+
| FIN |<---------------- ------------------>| CLOSE |
| WAIT-1 |------------------ | WAIT |
+---------+ rcv FIN \ +---------+
| rcv ACK of FIN ------- | CLOSE |
| -------------- snd ACK | ------- |
V x V snd FIN V
+---------+ +---------+ +---------+
|FINWAIT-2| | CLOSING | | LAST-ACK|
+---------+ +---------+ +---------+
| rcv ACK of FIN | rcv ACK of FIN |
| rcv FIN -------------- | Timeout=2MSL -------------- |
| ------- x V ------------ x V
\ snd ACK +---------+delete TCB +---------+
-------------------->|TIME-WAIT|------------------->| CLOSED |
+---------+ +---------+
Figure 5: TCP Connection State Diagram
注解 · 读图方法
左边一列是主动关闭路径:ESTAB → FIN-WAIT-1 → FIN-WAIT-2 → TIME-WAIT → CLOSED。右边是被动关闭:ESTAB → CLOSE-WAIT → LAST-ACK → CLOSED。中间 CLOSING 是双方同时 FIN。
原文 Note 2:若 FIN-WAIT-1 同时收到“对端 FIN + 对自己 FIN 的 ACK”,可直接进 TIME-WAIT(图上省略)。RST 可以从几乎任何状态跳出,图上也省略。
同一张图的手机可读版
颜色:墨框 = 过渡 · 青绿 = 可传数据 · 赤框 = 关闭尾声。与 Figure 5 对照,不是另一套规范。
基本三次握手
TCP Peer A TCP Peer B
1. CLOSED LISTEN
2. SYN-SENT --> <SEQ=100><CTL=SYN> --> SYN-RECEIVED
3. ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
4. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK> --> ESTABLISHED
5. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED
Figure 6: Basic Three-Way Handshake for Connection Synchronization[……节选逐行解说,下接 ACK 不占序号的原文]
Note that the sequence number of the segment in line 5 is the same as in line 4 because the ACK does not occupy sequence number space (if it did, we would wind up ACKing ACKs!).
注解
A 选 ISN=100,B 选 ISN=300。B 的 ACK=101 确认的是那个 SYN(占了序号 100)。A 的 ACK=301 确认 B 的 SYN。第四、第五拍 Seq 都是 101:纯 ACK 不占号。
第三次握手本身是确认对端的 SYN(Figure 6 第 4 行的纯 ACK)。迟到的旧 SYN 走的是另一条路:对端回 SYN+ACK 后,本端用 RST 拆掉这条误建连接(Figure 8),不要把它说成“第三次握手就是发 RST”。
同时打开(Figure 7)是两边都从 CLOSED 发 SYN,各自走过 SYN-SENT → SYN-RECEIVED → ESTABLISHED。实现必须支持(MUST-10),抓包里少见。
正常关闭:四次
TCP Peer A TCP Peer B
1. ESTABLISHED ESTABLISHED
2. (Close)
FIN-WAIT-1 --> <SEQ=100><ACK=300><CTL=FIN,ACK> --> CLOSE-WAIT
3. FIN-WAIT-2 <-- <SEQ=300><ACK=101><CTL=ACK> <-- CLOSE-WAIT
4. (Close)
TIME-WAIT <-- <SEQ=300><ACK=101><CTL=FIN,ACK> <-- LAST-ACK
5. TIME-WAIT --> <SEQ=101><ACK=301><CTL=ACK> --> CLOSED
6. (2 MSL)
CLOSED
Figure 12: Normal Close Sequence
注解
对端 FIN 必须被确认;本端 FIN 何时发取决于本方向关闭时机。两者语义独立,通常分开发,但本地应用已关闭时可同段 FIN+ACK(§3.6 Figure 12、§3.10.7.4)。
TIME-WAIT 通常是主动关闭方;同步关闭时双方均进入(§3.6 Figure 13)。被动单方关闭时,被动方从 LAST-ACK 直接 CLOSED。
线上看到三次,多半是本端在 ACK 对端 FIN 的同时已经可以发自己的 FIN,不是“挥手变成三次握手”。
抓包对照
实验室样本是三次握手。Wireshark 列 Seq / Ack / Win / Flags。相对序号默认从 0 起算,看 ISN 请关掉 Relative sequence numbers。
- 直接可见:端口、Seq、Ack、Data Offset、标志、窗口、校验和、紧急指针、选项(MSS、WS、SACK、TS)。
- 看不见:cwnd、RTO、ssthresh。那些是发送方本地状态,不在首部里。
- 重传:同一 Seq 再次出现。空洞:SACK 选项里的左右边缘。
考点与易错点
- SYN、FIN 各消耗一个序号;纯 ACK 不消耗。握手第三拍可以带数据。
- Ack 是“下一个期望字节”,累积确认,不是“只确认这一段”。
- 两次握手不够:无法确认反向通路,也无法用 RST 拒绝迟到的旧 SYN。
- 四次挥手是因为全双工:收到 FIN 后仍可能继续发数据。
- TIME-WAIT 通常是主动关闭方;同步关闭时双方均进入。时长 2MSL,防最后 ACK 丢失和旧报文串连接。
- 实际发送窗口 = min(rwnd, cwnd)。窗口字段只通告 rwnd;拥塞窗口不在报文里。