①TCP 报文段的整体结构
一个 TCP 报文段 = 头部 + 数据。头部固定 20 字节,加上可选字段后最长 60 字节(因为“数据偏移”字段只有 4 位,最大值 15,单位是 4 字节:15 × 4 = 60)。
固定头部
20 字节,必选。包含端口、序号、确认号、窗口、校验和等核心字段。
选项(Options)
0~40 字节,可选。常见 MSS、Window Scale、SACK、Timestamp,长度需 4 字节对齐。
数据(Payload)
应用层数据,最大 MSS(通常 1460 字节)。可以为空(如纯 ACK 报文)。
为什么头部要 4 字节对齐?“数据偏移”字段以 4 字节为单位表示头部长度,因此头部必须是 4 的整数倍,不足时用选项里的填充补齐。这也是 32 位字长处理器的历史遗留设计。
②头部位图(一行 = 32 位)
③字段逐一详解
| 字段 | 长度 | 作用 |
|---|---|---|
| 源端口 | 16 bit | 发送方的应用进程端口。取值范围 0~65535。 |
| 目的端口 | 16 bit | 接收方的应用进程端口(如 80、443)。端口 + IP 构成四元组标识一条连接。 |
| 序列号 seq | 32 bit | 本报文段第一个字节的编号。用于排序、去重、确认。 |
| 确认号 ack | 32 bit | 期望收到的下一个字节编号。仅当 ACK=1 时有效。 |
| 数据偏移 | 4 bit | 也叫首部长度,单位是 4 字节。值 5 表示 20 字节;最大 15 表示 60 字节。 |
| 保留 | 6 bit | 留作将来使用,置 0。 |
| 控制位 | 6 bit | URG / ACK / PSH / RST / SYN / FIN,见下一节。 |
| 窗口大小 | 16 bit | 接收方通告的 rwnd,用于流量控制。上限 65535,需要 Window Scale 扩容。 |
| 校验和 | 16 bit | 覆盖伪首部 + TCP 头 + 数据,检测传输损坏。 |
| 紧急指针 | 16 bit | 仅 URG=1 时有效,指出紧急数据在报文中的偏移。实际很少使用。 |
为什么校验和要包含“伪首部”?伪首部包含源 IP、目的 IP、协议号、TCP 长度等 IP 层信息。加入校验可以检测出“报文被错误路由到别的主机/协议”这类 IP 层才能发现的错误,弥补了分层之间的信任缺口。
④六个控制位:连接的“动词”
| 标志位 | 含义 | 典型场景 |
|---|---|---|
| SYN | 发起连接,同步序列号 | 三次握手第 1、2 步 |
| ACK | 确认号字段有效 | 握手建立后几乎所有报文都置 1 |
| FIN | 发送方数据发完,请求关闭本方向 | 四次挥手第 1、3 步 |
| RST | 强制重置连接(异常终止) | 端口未监听、连接不存在、应用崩溃后收到数据 |
| PSH | 提示接收方立即将数据交给应用层,别在缓冲区攒着 | 交互式应用(SSH、Telnet) |
| URG | 报文含紧急数据,配合紧急指针 | 极少使用 |
易错点:很多人以为“ACK 标志位”等于“确认号”。其实 ACK=1 只是说“确认号字段有效”;真正的确认值在 32 位的确认号字段里。握手第 1 个报文 ACK=0,所以它的确认号字段被忽略。
⑤常见选项字段(面试加分项)
| 选项 | 作用 | 为什么需要 |
|---|---|---|
| MSS(最大报文段长度) | 声明自己能接收的最大数据长度(通常 1460) | 在三次握手时协商,避免发送数据过大导致 IP 层分片。 |
| Window Scale(窗口扩大因子) | 把窗口值左移 N 位,最大可扩展到约 1GB | 16 位窗口上限只有 65535 字节,在长肥管道(高带宽高延迟)下远远不够。 |
| SACK Permitted | 协商启用选择性确认 | 让接收方能告知不连续的已收区间,发送方只重传真正丢失的段。 |
| Timestamp | 时间戳,用于精确测量 RTT、防止序号回绕(PAWS) | 高速网络下 32 位序列号可能在短时间内回绕,时间戳可区分新旧报文。 |
Window Scale 举个例子:窗口字段值是 1000,Window Scale 选项协商为 7,则实际窗口 = 1000 × 2⁷ = 128000 字节。它同样在三次握手的 SYN 报文中协商,之后整条连接固定不变。
Wireshark 视角:一个真实报文长啥样
Transmission Control Protocol, Src Port: 54321, Dst Port: 443, Seq: 1, Ack: 1, Len: 0
Source Port: 54321
Destination Port: 443
Sequence Number: 1
Acknowledgment Number: 1
0101 .... = Header Length: 20 bytes (5)
Flags: 0x010 (ACK)
000. .... .... = Reserved
...0 .... .... = Nonce: Not set
.... 0... .... = Congestion Window Reduced: Not set
.... .0.. .... = ECN-Echo: Not set
.... ..0. .... = Urgent: Not set
.... ...1 .... = Acknowledgment: Set
.... .... 0... = Push: Not set
.... .... .0.. = Reset: Not set
.... .... ..0. = Syn: Not set
.... .... ...0 = Fin: Not set
Window: 65535
Checksum: 0x8a3f
Urgent Pointer: 0
Options: (12 bytes), No-Operation, SACK Permitted, Timestamps
头部长度是 20 + 12 = 32 字节(数据偏移 = 8,8 × 4 = 32)。注意头部是 4 字节对齐的,所以选项区的 12 字节不需要额外填充。
⑥面试高频追问
Q1:TCP 头部最小多少字节?最大多少?
固定部分 20 字节;加上最多 40 字节选项后最大 60 字节。因为“数据偏移”字段是 4 bit,最大值 15,单位是 4 字节,15 × 4 = 60。Q2:数据偏移(首部长度)的单位是什么?
4 字节。所以它的值 5 表示 20 字节头部,15 表示 60 字节。Q3:为什么需要 Window Scale 选项?
窗口字段只有 16 位,最大通告 65535 字节。在高带宽高延迟的“长肥管道”上,这点窗口远远填不满带宽(带宽时延积可能达到几百 KB 甚至 MB)。Window Scale 通过左移把窗口逻辑上扩大到约 1GB。Q4:MSS 和 MTU 什么关系?在哪协商?
MSS = MTU − IP头(20) − TCP头(20),以太网下通常 1500 − 40 = 1460。MSS 在三次握手的 SYN 报文中通过选项相互通告,双方取较小值使用,目的是让 TCP 层就把数据切好,避免 IP 层分片。Q5:ACK 标志位和确认号字段有什么区别?
ACK=1 是开关,表示“确认号字段有效”;确认号字段才是具体的期望字节序号。第一个 SYN 报文 ACK=0,其确认号字段无意义。Q6:RST 什么时候会出现?
端口未监听、连接已不存在却收到数据、应用异常崩溃后收到报文、或主动拒绝连接时。RST 是异常终止,会丢弃缓冲区未读数据,与 FIN 的优雅关闭不同。Q7:TCP 校验和为什么要加伪首部?
伪首部含源/目的 IP、协议号、TCP 长度。加入校验可检测报文被错误路由等 IP 层错误,弥补分层设计的信任缺口。Q8:序列号是 32 位,会不会用完?
会回绕。高速网络下 32 位(约 4GB)序列号可能很快循环,因此引入 Timestamp 选项的 PAWS 机制来区分新旧报文,避免回绕导致旧报文被误收。✓一句话速记
头部 20~60 字节;seq 是本段首字节,ack 是期待下一字节;数据偏移以 4 字节为单位所以头部最长 60;窗口 16 位不够用要靠 Window Scale 扩容;MSS 在握手时协商好,目的就是避免 IP 分片。