Appearance
TCP 协议基础
2026 大纲 五(三)1 TCP 段。首部字段的位数、单位、极值与选项容量集中在本篇;校验和的反码求和算法见《UDP 协议》,seq/ack 的逐报文推演见《TCP 连接管理》。
一、五个特点,"面向连接"是根
上一篇把 TCP 与 UDP 的分界定在"两端有没有各存一份对端状态"上。从这一句出发,TCP 教科书式的五个特点全都能推出来,不必分开记。
面向连接 = 两端各存一份对端状态。于是——
状态是成对的,一份状态只能对着一个对端 ⟹ 只能点对点,不支持广播与多播。 状态里能存序号与确认信息 ⟹ 可靠交付:无差错、不丢失、不重复、按序到达。 状态里能存两个方向各自的缓存与窗口 ⟹ 全双工。 有了字节序号,数据怎么切都能拼回 ⟹ 面向字节流——TCP 把应用交下来的数据仅仅看成一连串无结构的字节流,并不知道其含义。
五条里只有第一条要记,其余四条是推论。
交互可视化
二、报文段首部
| 字段 | 长度 | 单位 | 说明 |
|---|---|---|---|
| 源端口 / 目的端口 | 各 16 位 | — | 与 UDP 同 |
| 序号 seq | 32 位 | 字节 | 本报文段数据部分第一个字节的编号 |
| 确认号 ack | 32 位 | 字节 | 期望收到的下一个字节的编号,隐含"之前全部收到"(累积确认) |
| 数据偏移 | 4 位 | 4 字节 | TCP 首部长度。最小 5(=20 字节),最大 15(=60 字节) |
| 保留 | 6 位 | — | 保留未用,置 0 |
| 标志位 | 各 1 位 | — | URG / ACK / PSH / RST / SYN / FIN |
| 窗口 | 16 位 | 字节 | 发送本报文段一方的接收窗口 |
| 校验和 | 16 位 | — | 检验首部 + 数据,计算时加 12 字节伪首部(同 UDP,协议号改 6、长度改 TCP 长度) |
| 紧急指针 | 16 位 | 字节 | 仅当 URG=1 有效,指出紧急数据的末尾在报文段中的位置 |
| 选项 | 可变,最长 40 字节 | — | MSS、窗口扩大、时间戳、SACK 等 |
| 填充 | 可变 | — | 使整个首部长度为 4 字节的整数倍 |
首部最少 20 字节(不用选项时),最多 60 字节(20 固定 + 选项最多 40)。而这个 60 的上限只有一个源头,值得单独推一遍。
数据偏移字段只有 4 位,最大值 15。 如果单位取 1 字节,首部最长就只有 15 字节——连 20 字节的固定首部都装不下。所以它必须放大单位;而首部总长度本来就要求是 4 字节的整数倍(这正是选项后面要填充的原因),取 4 字节作单位不损失任何精度,还把 4 位字段的表达能力放大了 4 倍。它是被字段宽度逼出来的唯一可行解。
于是两个换算式:首部字节数 = 数据偏移 × 4,选项字节数 = 数据偏移 × 4 − 20。40 字节的选项容量、后面 SACK"最多 4 个块",全都由这一处推出来。
窗口字段:填的是"我能收多少"
这个字段最容易记反:它是发送本报文段一方的接收窗口,不是自己的发送窗口。甲发给乙的报文段里写着窗口 1000,意思是"我(甲)还能再收 1000 字节",是在限制乙。
还有一个起点问题:窗口要从本报文段的确认号算起。确认号 701、窗口 1000,意味着对方可以发的是字节 701~1700。
16 位使它的上限止步于 65535 字节 ≈ 64 KB,这个限制后面靠窗口扩大选项突破。
六个标志位
| 标志位 | 全称 | 含义 |
|---|---|---|
| URG | Urgent | 紧急位。URG=1 时紧急指针有效,紧急数据被插到本报文段数据的最前面,接收方尽快传送而不按排队顺序 |
| ACK | Acknowledgment | 确认位。仅当 ACK=1 时确认号字段才有效。连接建立后所有传送的报文段都必须把 ACK 置 1 |
| PSH | Push | 推送位。发送方立即创建报文段发出,接收方尽快向上交付,不等缓存填满。实际很少使用 |
| RST | Reset | 复位位。连接中出现严重差错必须释放后重建;也用来拒绝一个非法的报文段或拒绝打开一个连接 |
| SYN | Synchronize | 同步位。SYN=1 且 ACK=0 是连接请求;SYN=1 且 ACK=1 是同意建立连接 |
| FIN | Finish | 终止位。本方数据已发送完毕,要求释放连接 |
一条线索串起来:建连用 SYN+ACK,拆连用 FIN+ACK,出错用 RST,插队用 URG,催交付用 PSH。
URG 与 PSH 催的不是同一件事,这一对最容易混:URG 改的是发送顺序(紧急数据插到本报文段数据的最前面),PSH 改的是交付时机(接收方立即上交,不等缓存填满)。还有一条边界:零窗口时仍然可以发送紧急数据。
SYN 与 FIN 各消耗一个序号,即使它们不携带任何数据;而不携带数据的纯 ACK 不消耗序号。所以确认号 = 对方 seq + 该报文段消耗的序号数——这条是下一篇所有序号计算题的起点。
TCP 首部的 32 位位图与首部开销的量级(想看清字段排布、或想弄清"利用率不超过 1/41"这个数从哪来时展开)
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源端口号 | 目的端口号 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 序号 (seq) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 确认号 (ack) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据偏移 | 保留 |U|A|P|R|S|F| 窗口大小 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 校验和 | 紧急指针 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 选项(长度可变)+ 填充 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+一行 32 位,正好对应"数据偏移以 4 字节为单位"里的那个 4 字节。数据偏移 = 8 ⟹ 首部 32 字节 ⟹ 选项 12 字节。
首部开销的量级:
为什么减两个 20 而不是一个:MSS 的定义是"不分片时数据字段能有多长",而 IP 层要看的是整个 IP 数据报不超过 MTU,IP 数据报 = IP 首部 + TCP 首部 + 数据,所以两个首部都要扣。
| 发法 | 段数 | 每段数据 | 线路上的总字节 | 有效载荷率 |
|---|---|---|---|---|
| 按 MSS 装满 | 前 3 段各 1452,末段 | |||
| 每次只发 1 字节(Telnet 那种交互式输入) | 5000 | 1 |
段数要向上取整:TCP 不能把一个字节劈成两半,装不满的那部分必须单独成段。
下面那一行就是教材"当 TCP 报文段只含有 1 字节的数据时……对网络的利用率就不会超过
三、MSS:最大报文段长度
它是数据字段的最大长度,不含 TCP 首部——教材点名过这个措辞:"MSS 并不是整个 TCP 报文段的最大长度,而是'TCP 报文段长度减去 TCP 首部长度'"。
取值是效率的两头权衡:太小则数据至少要背 40 字节首部(TCP 20 + IP 20),极端情形下数据只有 1 字节、网络利用率不超过
两条最容易记岔的边界要按住。
MSS 与接收窗口没有关系。 教材专门点过:规定 MSS 并不是考虑接收缓存可能放不下。它由 MTU 决定,目的只有一个——不触发 IP 分片。
MSS 是通知,不是协商。 教材同样点名"连接建立时双方协商 MSS"是错误说法——各自在 SYN 里通知对方,两个方向可以不同。未填写时默认 536 字节(
四、常见选项
| 选项 | 长度 | 作用 |
|---|---|---|
| MSS | 4 字节 | 在 SYN 报文段中通知本方能接收的最大报文段长度 |
| 窗口扩大 | 3 字节 | 携带一个移位值 |
| 时间戳 | 10 字节 | 时间戳值 4 字节 + 时间戳回送回答 4 字节,另 2 字节为种类与长度 |
| SACK | 可变 | 选择确认,报告已收到的不连续字节块的边界 |
| NOP / EOL | 1 字节 | 填充与对齐 |
窗口扩大解的是长肥管道(传播时延与带宽都很大,如卫星信道)上 64 KB 不够用的问题:
时间戳的两个功能是同一个机制的两面:它给报文段打上时间标签,于是"这个 ACK 对应哪次发送"(准确测 RTT,解开 Karn 算法"重传样本不能用"的死结)与"这个报文段属于哪一轮"(PAWS,防序号绕回)都能回答了——序号只表达"第几个字节",时间戳补上"什么时候"。
序号绕回是个真实存在的问题:绕回时间
SACK 最多报 4 个块,这个数也是从首部长度上限推出来的:每块 8 字节(左右边界各 4)+ 2 字节种类与长度,4 块共 34 ≤ 40,5 块要 42 > 40。上限的源头仍然是那句"选项最多 40 字节"。
选项总长度必须是 4 字节的整数倍,不足处用 NOP 或 EOL 填充。
可靠传输为什么放在传输层而不是网络层(想弄清端到端原则时展开)
判据是端到端原则:网络核心(路由器)只做最基本的转发,复杂的可靠性交给端系统。三条理由——① 网络核心保持简单才能高速;② 不同应用需要的可靠性不同,放在网络层等于强迫所有应用(包括视频通话)承受开销;③ 即使每一跳都可靠,端系统内部仍可能出错,最终还是要在端系统做一次端到端校验,那么中间那些逐跳的可靠性就成了重复投入。
本节小结
- "面向连接"是五个特点的根:面向连接 = 两端各存一份对端状态,由此推出点对点、可靠交付、全双工、面向字节流。
- 首部 20~60 字节的上限只有一个源头:数据偏移 4 位 → 最大 15 → 单位 4 字节 → 首部
→ 选项 → SACK 最多报 4 个块。窗口字段填的是对方能收多少且要从确认号算起,16 位使它止步于 64 KB,靠窗口扩大选项突破。 - MSS 由 MTU 决定、与接收窗口无关,且是通知而非协商,两个方向可以不同、未填写默认 536 字节;时间戳选项的两个功能(准确测 RTT、防序号绕回 PAWS)本质是同一件事——给报文段补上"什么时候"这一维。
考点速记
本篇在真题里被考过的形式只有一种:问某个动作依据的是首部里哪个字段。
UDP 实现分用时依据的头部字段(cn-2018-39)。四个候选是源端口号、目的端口号、长度、校验和,答 B:目的端口号。
判据是"分用是谁的动作":分用发生在接收方,动作是"把这份数据交给本机的哪个进程"。目的端口号标识的正是本机上的那个进程,所以它是唯一的依据。源端口号标识的是对方的进程,接收方拿它来填回信的目的端口,与"交给谁"无关;长度和校验和更是与寻址无关。
这道题看着简单,但它卡的是一条容易含糊的边界。 上一篇讲过 UDP 按目的二元组分用、TCP 按四元组分用——注意 TCP 的四元组里也含源端口号,可那是用来区分不同连接的,不是用来找进程的。这道题问的是 UDP,答案干干净净只有目的端口号一个。
本篇其余内容——首部各字段的位数与单位、六个标志位、MSS 的算法、四种选项——在真题里不单独成题。它们不出现在本篇的练习区里,却是后面五篇几乎所有计算题的字典:
"数据偏移 × 4 = 首部字节数" 是 cn-2012-47 从 hex dump 里读 TCP 首部的前提;"SYN 与 FIN 各消耗一个序号、纯 ACK 不消耗" 是 cn-2019-39、cn-2020-39、cn-2026-47 全部序号题的唯一依据;"窗口字段填的是发送方自己的接收窗口" 是 cn-2010-39、cn-2021-40、cn-2025-38 判断"还能发多少"的起点;"MSS 是数据字段长度、不含首部" 则是 cn-2021-39 算传输效率时不踩坑的关键。这八道题都不在本篇的练习区里,各自的完整解法见对应的那一篇。
本篇练习区里还会出现一道 cn-2014-39,问 UDP 的三条叙述哪几条正确,讲在 TCP 与 UDP 对比。
易错:分用依据的是目的端口号。 源端口号标识对方的进程,用来填回信,与"交给谁"无关。
易错:数据偏移的单位是 4 字节。 首部字节数 = 数据偏移 × 4,选项字节数 = 数据偏移 × 4 − 20。
易错:窗口字段填的是"发送本报文段一方的接收窗口",不是自己的发送窗口;而且要从本报文段的确认号算起。
易错:SYN 与 FIN 各消耗一个序号,纯 ACK 不消耗。 序号计算题全靠这条。
易错:MSS 是数据字段的最大长度,不含 TCP 首部,而且要从 MTU 里减掉 IP 与 TCP 两个首部。
易错:MSS 与接收窗口无关,也不是协商出来的;窗口扩大选项才是真协商。
易错:URG 改发送顺序,PSH 改交付时机。 零窗口时仍可发送紧急数据。
易错:连接建立后所有报文段都必须把 ACK 置 1。 只有第一次握手的 SYN 段 ACK=0。
教材出处
- 谢希仁《计算机网络》(第 8 版)p219(5.3.1 TCP 最主要的特点):五条特点的原文,包括"TCP 提供可靠交付的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达",以及面向字节流的定义"TCP 把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。TCP 并不知道所传送的字节流的含义"。
- 同书 p227(5.5 TCP 报文段的首部格式):各标志位的定义。ACK——"仅当 ACK=1 时确认号字段才有效……TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置为 1";PSH——"接收方 TCP 收到 PSH=1 的报文段,就尽快地(即'推送'向前)交付接收应用进程,而不再等到整个缓存都填满了后再向上交付",并注明"推送操作很少使用";RST——"将 RST 置为 1 还用来拒绝一个非法的报文段或拒绝打开一个连接";SYN——"当 SYN=1 而 ACK=0 时,表明这是一个连接请求报文段"。同页还有窗口字段的关键限定:"窗口指的是发送本报文段的一方的接收窗口(而不是自己的发送窗口)……从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量",以及"确认号 701、窗口 1000"那个例子。
- 同书 p228:MSS 的定义与两头权衡——"MSS 并不是整个 TCP 报文段的最大长度,而是'TCP 报文段长度减去 TCP 首部长度'";"这并不是考虑接收方的接收缓存可能放不下……实际上,MSS 与接收窗口值没有关系";"当 TCP 报文段只含有 1 字节的数据时,在 IP 层传输的数据报的开销至少有 40 字节……对网络的利用率就不会超过 1/41";"MSS 应尽可能大些,只要在 IP 层传输时不需要再分片就行";"若主机未填写这一项,则 MSS 的默认值是 536 字节……所有互联网上的主机都应能接受的报文段长度是 536+20=556 字节"。同页脚注即"协商 MSS 是错误说法"那条。此页还给出选项与填充的规则:"选项 长度可变,最长可达 40 字节。当没有使用'选项'时,TCP 的首部长度是 20 字节。最后的填充字段仅仅是为了使整个 TCP 首部长度是 4 字节的整数倍。"
- 同书 p229:窗口扩大选项与时间戳选项——"窗口扩大选项占 3 字节,其中有一个字节表示移位值 S。新的窗口值等于 TCP 首部中的窗口位数从 16 增大到 (16+S)。移位值允许使用的最大值是 14,相当于窗口最大值增大到
";"时间戳选项占 10 字节",两个功能为计算 RTT 与"防止序号绕回 PAWS",并给出可复核的数据"当使用 1.5 Mbit/s 的速率发送报文段时,序号重复要 6 小时以上。但若用 2.5 Gbit/s 的速率发送报文段,则不到 14 秒序号就会重复"。 - 同书 p220(5.3.2 TCP 的连接):连接 = 套接字对的定义式,本篇"四元组"一节的依据。
相关知识
TCP 与 UDP 对比|UDP 协议|TCP 连接管理|TCP 可靠传输