Skip to content

TCP 协议基础

2026 大纲 五(三)1 TCP 段。首部字段的位数、单位、极值与选项容量集中在本篇;校验和的反码求和算法见《UDP 协议》,seq/ack 的逐报文推演见《TCP 连接管理》。

一、五个特点,"面向连接"是根

上一篇把 TCP 与 UDP 的分界定在"两端有没有各存一份对端状态"上。从这一句出发,TCP 教科书式的五个特点全都能推出来,不必分开记。

面向连接 = 两端各存一份对端状态。于是——

状态是成对的,一份状态只能对着一个对端 ⟹ 只能点对点,不支持广播与多播。 状态里能存序号与确认信息可靠交付:无差错、不丢失、不重复、按序到达。 状态里能存两个方向各自的缓存与窗口全双工有了字节序号,数据怎么切都能拼回面向字节流——TCP 把应用交下来的数据仅仅看成一连串无结构的字节流,并不知道其含义。

五条里只有第一条要记,其余四条是推论。

交互可视化

加载可视化中...

二、报文段首部

字段长度单位说明
源端口 / 目的端口各 16 位与 UDP 同
序号 seq32 位字节本报文段数据部分第一个字节的编号
确认号 ack32 位字节期望收到的下一个字节的编号,隐含"之前全部收到"(累积确认)
数据偏移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,这个限制后面靠窗口扩大选项突破。

六个标志位

标志位全称含义
URGUrgent紧急位。URG=1 时紧急指针有效,紧急数据被插到本报文段数据的最前面,接收方尽快传送而不按排队顺序
ACKAcknowledgment确认位。仅当 ACK=1 时确认号字段才有效连接建立后所有传送的报文段都必须把 ACK 置 1
PSHPush推送位。发送方立即创建报文段发出,接收方尽快向上交付,不等缓存填满。实际很少使用
RSTReset复位位。连接中出现严重差错必须释放后重建;也用来拒绝一个非法的报文段或拒绝打开一个连接
SYNSynchronize同步位。SYN=1 且 ACK=0 是连接请求;SYN=1 且 ACK=1 是同意建立连接
FINFinish终止位。本方数据已发送完毕,要求释放连接

一条线索串起来:建连用 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 字节。

首部开销的量级:1/41 是怎么来的。 每个报文段都要背 20 字节 TCP 首部 + 20 字节 IP 首部,这 40 字节与数据多少无关。把同样的 5000 字节数据用两种方式发出去,差距立刻显出来——设某路径 MTU = 1492 字节(PPPoE 链路的典型值),两个首部均为 20 字节且不含选项:

MSS=14922020=1452 字节

为什么减两个 20 而不是一个:MSS 的定义是"不分片时数据字段能有多长",而 IP 层要看的是整个 IP 数据报不超过 MTU,IP 数据报 = IP 首部 + TCP 首部 + 数据,所以两个首部都要扣。

发法段数每段数据线路上的总字节有效载荷率
按 MSS 装满5000/1452=4前 3 段各 1452,末段 50003×1452=6444×(20+20)+5000=51605000/5160=96.90%
每次只发 1 字节(Telnet 那种交互式输入)500015000×41=2050005000/205000=2.44%

段数要向上取整:TCP 不能把一个字节劈成两半,装不满的那部分必须单独成段。

下面那一行就是教材"当 TCP 报文段只含有 1 字节的数据时……对网络的利用率就不会超过 1/41"的出处——1/41=2.44%,而且到了链路层还要再加开销。这正是 Nagle 算法存在的理由:把零散的小块攒起来再发,就是把载荷率从 2.44% 那一行拉回 96.90% 那一行。

三、MSS:最大报文段长度

MSS=MTUIP 首部长度TCP 首部长度

它是数据字段的最大长度,不含 TCP 首部——教材点名过这个措辞:"MSS 并不是整个 TCP 报文段的最大长度,而是'TCP 报文段长度减去 TCP 首部长度'"。

取值是效率的两头权衡:太小则数据至少要背 40 字节首部(TCP 20 + IP 20),极端情形下数据只有 1 字节、网络利用率不超过 1/41太大则 IP 层要分片、终点要重装、出错还要重传。结论是"尽可能大,只要在 IP 层传输时不需要再分片就行"。但路径是动态变化的,某条路径上确定的不分片 MSS 改走另一条就可能需要分片,所以最佳 MSS 实际上很难确定。

两条最容易记岔的边界要按住。

MSS 与接收窗口没有关系。 教材专门点过:规定 MSS 并不是考虑接收缓存可能放不下。它由 MTU 决定,目的只有一个——不触发 IP 分片。

MSS 是通知,不是协商。 教材同样点名"连接建立时双方协商 MSS"是错误说法——各自在 SYN 里通知对方,两个方向可以不同。未填写时默认 536 字节(5762020),对应报文段总长 556 字节。

四、常见选项

选项长度作用
MSS4 字节在 SYN 报文段中通知本方能接收的最大报文段长度
窗口扩大3 字节携带一个移位值 S,把窗口字段的有效位数从 16 位增大到 16+S
时间戳10 字节时间戳值 4 字节 + 时间戳回送回答 4 字节,另 2 字节为种类与长度
SACK可变选择确认,报告已收到的不连续字节块的边界
NOP / EOL1 字节填充与对齐

窗口扩大解的是长肥管道(传播时延与带宽都很大,如卫星信道)上 64 KB 不够用的问题:Smax=14,窗口最大值升到 2301在双方初始建立连接时协商(这个确实是协商,和 MSS 不同),不再需要时可发 S=0 回到 16 位。

时间戳的两个功能是同一个机制的两面:它给报文段打上时间标签,于是"这个 ACK 对应哪次发送"(准确测 RTT,解开 Karn 算法"重传样本不能用"的死结)与"这个报文段属于哪一轮"(PAWS,防序号绕回)都能回答了——序号只表达"第几个字节",时间戳补上"什么时候"。

序号绕回是个真实存在的问题:绕回时间 =232×8/R。教材给的数据是——1.5 Mbit/s 下要 6 小时以上,2.5 Gbit/s 下不到 14 秒。而典型的 MSL 是 2 分钟,序号绕得比报文段"寿终正寝"还快,就无法仅凭序号区分新旧报文段了

SACK 最多报 4 个块,这个数也是从首部长度上限推出来的:每块 8 字节(左右边界各 4)+ 2 字节种类与长度,4 块共 34 ≤ 40,5 块要 42 > 40。上限的源头仍然是那句"选项最多 40 字节"。

选项总长度必须是 4 字节的整数倍,不足处用 NOP 或 EOL 填充。

可靠传输为什么放在传输层而不是网络层(想弄清端到端原则时展开)

判据是端到端原则:网络核心(路由器)只做最基本的转发,复杂的可靠性交给端系统。三条理由——① 网络核心保持简单才能高速;② 不同应用需要的可靠性不同,放在网络层等于强迫所有应用(包括视频通话)承受开销;③ 即使每一跳都可靠,端系统内部仍可能出错,最终还是要在端系统做一次端到端校验,那么中间那些逐跳的可靠性就成了重复投入。

本节小结

  1. "面向连接"是五个特点的根:面向连接 = 两端各存一份对端状态,由此推出点对点、可靠交付、全双工、面向字节流。
  2. 首部 20~60 字节的上限只有一个源头:数据偏移 4 位 → 最大 15 → 单位 4 字节 → 首部 60 → 选项 40 → SACK 最多报 4 个块。窗口字段填的是对方能收多少且要从确认号算起,16 位使它止步于 64 KB,靠窗口扩大选项突破。
  3. 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,相当于窗口最大值增大到 2301";"时间戳选项占 10 字节",两个功能为计算 RTT 与"防止序号绕回 PAWS",并给出可复核的数据"当使用 1.5 Mbit/s 的速率发送报文段时,序号重复要 6 小时以上。但若用 2.5 Gbit/s 的速率发送报文段,则不到 14 秒序号就会重复"。
  • 同书 p220(5.3.2 TCP 的连接):连接 = 套接字对的定义式,本篇"四元组"一节的依据。

相关知识

TCP 与 UDP 对比UDP 协议TCP 连接管理TCP 可靠传输

真题练习

相关真题(2题)