TCP 头里每个字段到底在干什么?序号、确认号怎么对应?SYN 里那串选项各是什么?这篇在 en0 上抓一次真实的 HTTP 连接,逐个包逐字段解码,再用 lo0 看标志位的分布和已经被淘汰的 URG。
# 方向 源端口→目的端口 相对序号 相对确认号 头长 标志 窗口 载荷 校验和
1 → C→80 0 0 44 CWR+ECE+SYN 65535 0 0x3e01
2 ← 80→C 0 1 40 ECE+ACK+SYN 65535 0 0x98e8
3 → C→80 1 1 32 ACK 2061 0 0xbef2
4 → C→80 1 1 32 ACK+PSH 2061 56 0x4c99
5 ← 80→C 1 57 32 ACK 16 0 0xc5fa
6 ← 80→C 1 57 32 ACK+PSH 16 923 0x5171
7 ← 80→C 924 57 32 ACK+PSH 16 5 0x7e2f
8 → C→80 57 929 32 ACK 2047 0 0xb99c
9 ← 80→C 929 57 32 ACK+FIN 16 0 0xc250
整个连接共 12 个包。每个包的头都是 20 字节固定部分 + 选项:源端口 2、目的端口 2、序号 4、确认号 4、数据偏移 4 位 + 保留 4 位(合 1 字节)、标志 1 字节(CWR ECE URG ACK PSH RST SYN FIN)、窗口 2、校验和 2、紧急指针 2
第 1 个包(SYN)的头 20 字节:c080 0050 7432 eaec 0000 0000 b0c2 ffff 3e01 0000;数据偏移 = 11(×4 = 44 字节),保留位 0,标志字节 0xc2源端口、目的端口、序号、确认号、数据偏移、标志、窗口、校验和、紧急指针,共 20 字节。SYN 和 FIN 各占一个序号,所以 ACK 的确认号比对方的序号多 1。
SYN 的选项 24 字节:02 04 05 b4 01 03 03 06 01 01 08 0a 5f 0a 2f 86 00 00 00 00 04 02 00 00
MSS(类型 2,长度 4):MSS = 1460
NOP(1 字节,用来对齐 / 结束)
WScale(类型 3,长度 3):窗口缩放移位 6(窗口字段 × 2^6)
NOP(1 字节,用来对齐 / 结束)
NOP(1 字节,用来对齐 / 结束)
Timestamps(类型 8,长度 10):TSval = 1594503046,TSecr = 0
SACK-permitted(类型 4,长度 2):允许选择性确认
EOL(1 字节,用来对齐 / 结束)
SYN-ACK 的选项 20 字节:MSS、SACK-permitted、Timestamps、NOP、WScale
带数据的包头长 32 字节(选项 ['NOP', 'NOP', 'Timestamps'])、32 字节(选项 ['NOP', 'NOP', 'Timestamps'])
各种包的头长:{44: 1, 40: 1, 32: 10}——SYN 的头最长(选项最多),之后只剩时间戳(NOP NOP + 10 字节 = 12 字节),头 32 字节SYN 里一次性协商 MSS、窗口缩放、时间戳、SACK-permitted;之后每个包只保留时间戳(12 字节)。数据偏移字段告诉接收方头有多长。
下载 1048576 字节,lo0 上共 98 个 TCP 包;标志组合:ACK × 92;ACK+PSH × 2;SYN × 1;ACK+SYN × 1;ACK+PSH+FIN × 1;ACK+FIN × 1 窗口字段(16 位原始值):客户端发的 SYN 65535,之后客户端的 ACK 里最小 4085 / 最大 26523;SYN 的窗口字段不缩放(窗口缩放选项只对后面的包有效) 服务端发出的数据包:载荷最大 16332 字节(= MSS 16344),PSH 位出现 3 次——PSH 只是提示接收方尽快交给应用,不改变传输
握手之后每个包都带 ACK;PSH 只是提示;FIN 与 RST 结束连接。lo0 下载 1 MiB 的 98 个包里 92 个是纯 ACK。
客户端发出:标志 ACK+PSH,载荷 3 字节,紧急指针字段 0
客户端发出:标志 URG+ACK+PSH,载荷 1 字节,紧急指针字段 1
客户端发出:标志 ACK+PSH,载荷 3 字节,紧急指针字段 0
接收方 recv(MSG_OOB) 拿到 b'!';普通 recv 拿到 b'abc'
URG 标志置位时,紧急指针指向紧急数据的末尾(相对序号偏移);它几乎没有被实际用过,而且“带外数据”在各系统里语义不一致,RFC 6093 建议新应用不要使用紧急指针指向紧急数据的位置,MSG_OOB 发出的包能看到。语义不统一,不建议使用。