一、先把最容易混的地方捋顺:TCP“报文段”和 UDP“用户数据报”到底有什么区别
这部分在考研里很容易被一句“TCP 面向连接、UDP 无连接”带过去,但真正做题时,往往考的是更细的报文、字段、边界和机制差异。
先说一个很关键的表述:传输层里,UDP 的 PDU 通常叫“UDP 用户数据报”,TCP 的 PDU 通常叫“TCP 报文段”。再往下封装到网络层,统一都会变成 IP 数据报。也就是说,严格来说,常说的“TCP 数据包”和“UDP 数据包”只是口语化说法,考试里更规范的叫法还是“TCP 报文段”“UDP 用户数据报”。
二者最核心的差别,不只是“是否可靠”,而是“传输对象的组织方式”不同。
UDP 面向报文。应用层交给 UDP 一条报文,UDP 通常就按这一条报文来发送,接收方一次也按一个完整报文来交付。也就是说,UDP 保留应用层报文边界。发 3 次,就对应 3 个独立的 UDP 用户数据报;接收方不会把两次发送自动拼起来,也不会把一次发送自动拆成多次交付给应用层。
TCP 面向字节流。应用层看到的是连续字节序列,而不是一条一条独立消息。应用层即使分两次 write,也可能被 TCP 合并到一个报文段里发送;也可能一次 write 很大,被 TCP 拆成多个报文段发送。接收方拿到的也是连续字节流,因此 TCP 不保留应用层消息边界。这是 TCP 和 UDP 在“报文”层面最大的本质区别,也是考试里特别爱混淆的一点。
从首部看,UDP 首部很短,只有 8B,字段也少:源端口、目的端口、长度、检验和。它有长度字段,所以 UDP 用户数据报的总长度可以直接在 UDP 首部里看到。
TCP 首部最小 20B,可变长,因为可以带选项。它的字段明显更多:源端口、目的端口、序号、确认号、数据偏移、标志位、窗口、校验和、紧急指针,以及若干选项。也正因为 TCP 要实现可靠传输、流量控制、拥塞控制,所以它的首部远比 UDP 复杂。
可以把二者先记成这样:
| 对比项 | UDP | TCP |
|---|---|---|
| 连接方式 | 无连接 | 面向连接 |
| 可靠性 | 不保证可靠 | 可靠传输 |
| 传输对象 | 面向报文 | 面向字节流 |
| 是否保留消息边界 | 保留 | 不保留 |
| 首部长度 | 8B | 最小 20B,可变 |
| 是否有序 | 不保证 | 保证按序交付 |
| 流量控制 | 无 | 有 |
| 拥塞控制 | 无 | 有 |
| 典型单位 | UDP 用户数据报 | TCP 报文段 |
考试里还有一个常见陷阱:UDP 的“长度”是 UDP 首部字段之一;TCP 首部里没有专门的“总长度字段”,TCP 报文段长度要结合 IP 层长度来推。
二、TCP 报文段首部中最常考的标志字段有哪些
考研里最常考的是 6 个经典标志位,也就是:
URG、ACK、PSH、RST、SYN、FIN
现在很多资料还会看到 ECE、CWR,那是与 ECN 相关的扩展标志位。若是 408 风格或常规考研题,默认先把前面 6 个吃透,已经足够应对绝大多数题。
1. SYN:建立连接
SYN = Synchronize Sequence Numbers,用于建立连接时同步序号。
它最典型地出现在三次握手里。只要看到 SYN,基本就要联想到“连接建立”。并且要记住一个极其重要的规则:
SYN 会消耗一个序号。
这句话后面做三次握手题时非常关键。
2. ACK:确认有效
ACK 位置 1,表示“确认号字段有效”。
注意不是说“有 ACK 标志就一定只是在确认”,而是说“确认号这个字段此时可以用”。建立连接以后,几乎所有 TCP 报文段都会带 ACK=1。
考试里常见误区是把 ACK 理解成“确认报文段”。实际上,一个报文段可以同时带多个标志,比如 SYN + ACK,这在三次握手第二步里就会出现。
纯 ACK 本身不消耗序号。这也是做题的核心规则之一。
3. FIN:释放连接
FIN = Finish,表示发送方已经没有数据要发了,希望释放连接。
它主要用于四次挥手。和 SYN 一样:
FIN 也会消耗一个序号。
这是挥手题最容易错的地方之一。
4. RST:复位连接
RST = Reset,用于异常情况,表示连接出错,或者一方想强制中止连接。
比如访问一个不存在的端口,或者连接状态异常,可能收到 RST。考题里常把它和 FIN 对比:FIN 是正常结束,RST 是异常复位或强制中断。
5. PSH:尽快交付
PSH = Push,表示接收方应尽快把数据交给应用进程,而不要继续在缓冲区里等待。
这个标志位在考研中一般不会深挖实现细节,更重要的是知道它的含义:提示尽快上交应用层。
6. URG:紧急数据
URG = Urgent,表示紧急指针字段有效,报文段中有紧急数据,应优先处理。
这部分现在工程实践里不算常见,但考题里会把它作为首部字段识别题来考。记法很简单:URG 一出现,就要想到“紧急指针有效”。
三、TCP 首部中的窗口字段,到底表示什么
这个字段是很多人看了很多遍还是不扎实的地方,因为“窗口”这个词在数据链路层、传输层里都出现过,容易混。
TCP 首部里的“窗口”字段,通常指的是接收方通告窗口,也就是英文常说的 rwnd。
它的含义是:
接收方告诉发送方:我当前接收缓存里还能接收多少字节。
注意两个关键词。
第一,是“接收方通告”的。也就是说,这个字段不是发送方随便填的,而是接收方根据自己接收缓存的剩余空间,告诉对方一个数。
第二,单位是“字节”,不是“报文段个数”。这和很多链路层协议按帧编号、按帧计数很不一样。TCP 是按字节编号的,所以窗口本质上也是按字节度量的。
可以把它理解成一句非常直白的话:
“你最多还可以继续给我发这么多字节,再多我这边缓存可能就装不下了。”
所以 TCP 首部中的窗口字段体现的是流量控制思想。它解决的不是“网络堵不堵”的问题,而是“接收方来不来得及收”的问题。
四、发送方的窗口大小到底取决于什么
这是一个非常高频考点。
TCP 发送方真正能发送的数据量,不是只看接收方窗口,也不是只看网络拥塞情况,而是同时受两方面约束:
发送窗口 = min(rwnd, cwnd)
这里:
rwnd 是接收方通告窗口,反映接收方处理能力,属于流量控制。cwnd 是拥塞窗口,反映网络拥塞情况,属于拥塞控制。
所以真正的结论是:
发送方窗口大小取决于接收方通告窗口和拥塞窗口二者中较小者。
如果题目只考流量控制,往往说“发送窗口由接收方通告窗口决定”;
如果题目把拥塞控制也带进来,就要写更完整的版本:min(rwnd, cwnd)。
进一步说,发送方“此刻还能继续发送多少”,还要减去那些“已经发出但还没被确认的数据”。所以更细一点地理解是:
min(rwnd, cwnd)决定发送窗口上限- 已发送未确认的数据占用了一部分窗口
- 剩下那部分,才是当前还能再发的数据量
这个在计算题里会体现为“可发送窗口”。
五、MSS 到底是什么,和 MTU 有什么关系
MSS = Maximum Segment Size,最大报文段长度。
更准确地说,MSS 指的是:
一个 TCP 报文段中,数据部分的最大长度。
注意,是TCP 数据部分,不包括 TCP 首部,也不包括 IP 首部。
这个概念常和 MTU 一起出现。
- MTU:链路层最大传输单元,指一个链路层帧中能承载的网络层数据的最大长度
- MSS:TCP 一次愿意放进一个报文段里的最大 TCP 负载长度
在不考虑 IP/TCP 选项时,常见以太网环境下:
MSS = MTU - IP首部长度 - TCP首部长度
若以太网 MTU = 1500B,IPv4 首部 20B,TCP 首部 20B,则:
MSS = 1500 - 20 - 20 = 1460B
这也是一道非常常见的计算。
MSS 一般在三次握手时通过 TCP 选项协商。它的作用是尽量让 TCP 报文段大小合适,避免 IP 层分片。
六、三次握手怎么记,为什么是三次,不是两次
三次握手本质上干三件事:
- 客户端告诉服务器:我能发,你在吗
- 服务器告诉客户端:我能收也能发,我也在
- 客户端再告诉服务器:我知道你也能收发了
所以它不只是“打招呼”,而是双方都要确认彼此的发送和接收能力正常。
三次握手标准过程
设客户端初始序号为 x,服务器初始序号为 y。
第一次:
客户端 → 服务器SYN=1, seq=x
含义:请求建立连接。
注意:SYN 消耗一个序号,所以客户端下次发送的序号应从 x+1 开始。
第二次:
服务器 → 客户端SYN=1, ACK=1, seq=y, ack=x+1
含义:同意建立连接,同时确认收到了客户端的 SYN。
这里服务器自己的 SYN 也消耗一个序号,所以服务器后续序号从 y+1 开始。
第三次:
客户端 → 服务器ACK=1, seq=x+1, ack=y+1
含义:确认收到了服务器的 SYN。
记忆的核心规则只有三句
第一句:
谁发 SYN,谁的序号就加 1。
第二句:
确认号 = 对方序号 + 1(若对方发的是 SYN/FIN)或 对方序号 + 数据字节数。
第三句:
纯 ACK 不消耗序号。
你会发现,三次握手之所以看起来复杂,其实只是因为同时在记“两条方向各自的序号线”。一旦抓住“各算各的”,就不乱了。
客户端序号线:
x → x+1
服务器序号线:
y → y+1
它们彼此通过 ack 去确认对方已经走到了哪里。
为什么不能两次握手
考研常见表述是:两次握手无法防止失效的连接请求报文段突然又传到服务器,从而导致服务器错误建立连接。更通俗一点说,就是服务器没法确认客户端是否真的收到了自己的确认,也没法确认双方都已进入可通信状态。
所以第三次握手的本质,是让服务器知道:
“我发给你的 SYN+ACK,你确实收到了。”
七、四次挥手怎么记,为什么通常是四次
这块比三次握手更容易乱,因为它体现了 TCP 的全双工特性:两个方向的关闭是分开的。
四次挥手标准过程
设主动关闭方 A, 被动关闭方 B。
第一次:
A → BFIN=1, seq=u
表示 A 已经没有数据要发了。
注意:FIN 消耗一个序号,所以 A 后续序号变成 u+1。
第二次:
B → AACK=1, ack=u+1, seq=v
表示 B 知道 A 这边要关了。
这一步只是“确认”,并不代表 B 也立即关闭。
第三次:
B → AFIN=1, ACK=1, seq=w, ack=u+1
表示 B 自己的数据也发送完了,现在也请求关闭。
第四次:
A → BACK=1, seq=u+1, ack=w+1
表示确认收到 B 的 FIN。
为什么通常是四次,不是三次
因为 TCP 是全双工的。
A 不发了,只代表 A → B 这个方向关闭;
但 B → A 方向可能还有数据没发完,所以 B 先发 ACK,等自己数据发完后再发 FIN。
这就是“四次”的根本原因:两个方向分别关闭。
当然,在特殊情况下,B 第二次和第三次可以合并,也就是 ACK 和 FIN 一起发出去,但考试默认记标准四次挥手就够了。
四次挥手最实用的记忆法
只记一句最核心的话:
SYN 和 FIN 都要占一个序号,纯 ACK 不占。
于是所有题都可以机械推:
- 看到 SYN:序号 +1
- 看到 FIN:序号 +1
- 看到数据:序号 + 数据字节数
- 看到纯 ACK:序号不变
这比死背每一包长什么样更稳。
八、怎么记三次握手和四次挥手,不至于一做题就乱
这类题之所以让人觉得“包太多,太复杂”,本质原因不是包真的多,而是同时在跟踪:
- 客户端序号线
- 服务器序号线
- 哪些标志位消耗序号
- ack 到底在确认什么
真正高效的记法,不是背图,而是背规则。
第一条铁律:TCP 序号按字节编号
TCP 的 seq 不是“第几个报文段”,而是本报文段数据部分第一个字节的编号。
所以一旦带数据,序号前进量就是数据字节数。
第二条铁律:SYN、FIN 各占一个序号
这是做连接管理题最关键的规则。握手和挥手里,真正让序号 +1 的,往往就是 SYN 和 FIN。
第三条铁律:纯 ACK 不占序号
很多题错就错在把 ACK 也当成“占一个位置”。其实纯 ACK 只是确认,不携带新数据,也不申请建立/释放,因此不额外消耗序号。
第四条铁律:ack 表示“我期待收到你的下一个字节编号”
这句话特别重要。
所以 ack 不是“我收到了哪个编号”,而是“我已经收到了你前面的内容,下一次请从这个编号开始发”。
这样一来,ack = 已正确收到的最后一个字节编号 + 1
如果收到的是 SYN 或 FIN,因为它们也占一个序号,所以确认时也要加 1。
做题模板
以后凡是握手挥手题,建议直接画两条线:
上面写客户端序号变化,下面写服务器序号变化。
每来一个报文段,就只做三件事:
- 看谁发
- 看它带没带 SYN / FIN / 数据
- 改它自己的 seq,改对方给它的 ack
这么做会比背图稳得多。
九、例题:40Gb/s 的 TCP 多久会发生 32 位序号绕回
题目本质是在问:
TCP 序号字段 32 位,最多能表示 2^32 个不同序号。
如果一直高速发送数据,用完这一圈需要多长时间?
因为 TCP 序号是按字节编号的,所以可用字节数是一圈:
2^32 B
线路速率是:
40 Gb/s = 40 × 10^9 bit/s
换成字节每秒:
40 × 10^9 ÷ 8 = 5 × 10^9 B/s
于是发生序号绕回的时间为:
2^32 ÷ (5 × 10^9) s
又因为:
2^32 = 4.294967296 × 10^9
所以:
时间 ≈ 4.294967296 × 10^9 ÷ 5 × 10^9≈ 0.8589934592 s
约等于:
0.859 s
本题结论
TCP 在 40Gb/s 的线路上,若充分利用带宽,大约 0.859 秒就会发生一次 32 位序号绕回。
这题考什么
它考的是三个点:
第一,TCP 序号按字节编号,而不是按报文段编号。
第二,32 位序号空间是一圈 2^32。
第三,速率单位要从 bit/s 换成 B/s。
最容易错的地方
最常见错误有两个。
第一个错误,是把 2^32 当成 bit 数,而不是字节数。
第二个错误,是忘记 1B = 8bit,没有把 40Gb/s 换算成字节每秒。
十、TCP 的窗口机制和数据链路层滑动窗口、GBN 为什么“看起来很像”
你这个感觉完全对。它们确实有共同思想,所以看起来很像;但又不能直接画等号。
先说它们为什么像
它们都用了“滑动窗口”思想。
所谓滑动窗口,本质上就是:
- 发送方不必每发一份数据就停下来等确认
- 可以连续发送多个单位的数据
- 收到确认后,窗口向前滑动,继续发送后面的数据
这和停止-等待相比,效率明显高很多。所以数据链路层的 GBN、SR,以及传输层的 TCP,都使用了窗口思想。
它们也都涉及:
- 序号
- 确认
- 超时重传
- 连续发送
- 流水线传输
所以初学时把 TCP 想成“更复杂的滑动窗口协议”是很自然的。
十一、但 TCP 和 GBN 不能简单等同,差别很大
1. 所在层次不同
GBN、SR 是数据链路层可靠传输机制,通常解决的是一段链路上的帧传输问题。
TCP 是传输层协议,解决的是端到端进程之间的可靠传输问题。
这一点决定了 TCP 面对的环境更复杂。它跨越多个路由器、多个链路,必须考虑网络拥塞、接收缓存、端到端时延变化等问题,而链路层窗口协议往往只针对单跳链路。
2. 编号单位不同
GBN 一般按“帧”编号。
TCP 按“字节”编号。
这会直接影响做题方式。TCP 的 seq 和 ack 都是字节级的,因此一个报文段发送了多少字节,序号就推进多少。
3. TCP 同时做流量控制和拥塞控制,GBN 主要不是干这个的
GBN 的重点是可靠传输和差错恢复。
TCP 除了可靠传输,还要做:
- 流量控制:别把接收方撑爆
- 拥塞控制:别把网络打爆
所以 TCP 的发送窗口不是一个简单固定窗口,而是同时受 rwnd 和 cwnd 影响。
这也是 TCP 比 GBN 复杂得多的根本原因。
4. 确认机制相似,但 TCP 更灵活
经典 GBN 是累计确认,也就是确认到某一帧为止之前都收到了。
TCP 默认也是累计确认,所以这也是你觉得它像 GBN 的一个重要原因。
但 TCP 比 GBN 灵活得多。现代 TCP 中可能还有:
- 延迟确认
- 重复 ACK
- 快重传
- 选择确认 SACK
所以 TCP 不是教材里那个“纯粹的 GBN”。它只是保留了“累计确认”这一核心味道。
5. 失序处理方式不同
经典 GBN 中,接收方通常丢弃失序到达的帧,只确认按序到达的最后一帧。
TCP 在教材层面常强调“累计确认、按序交付”,所以也有类似味道;但实际实现里,TCP 往往会缓存失序报文段,并借助 SACK 等机制优化重传。
所以从考研做题角度,可以记成:
TCP 在确认风格上更接近累计确认,但整体并不等同于 GBN。
6. 重传策略不同
GBN 一旦某帧丢失,发送方超时后往往从该帧开始,把后面已经发过的都重传。
TCP 不一定这样“整段回退”,它有更复杂的重传判断方式,例如基于超时、基于重复 ACK 的快重传等。
十二、怎么在考试里快速区分“TCP 窗口”和“数据链路层滑动窗口”
我觉得可以抓下面这条主线:
如果题目强调“端到端、字节流、接收窗口、拥塞窗口、三次握手、四次挥手”
那基本就是 TCP 视角。
如果题目强调“帧编号、发送窗口 WT、接收窗口 WR、GBN、SR、停止等待、链路利用率”
那基本就是数据链路层可靠传输视角。
再进一步压缩成一句口诀:
链路层窗口重在差错恢复,TCP 窗口还要兼顾流量控制和拥塞控制。
十三、这一部分最容易错的点,最好单独记一下
第一,UDP 面向报文,保留消息边界;TCP 面向字节流,不保留消息边界。
第二,TCP 的序号和确认号都是按字节编号,不是按报文段编号。
第三,SYN 和 FIN 各消耗一个序号,纯 ACK 不消耗。
第四,TCP 首部中的窗口字段是接收方通告窗口,体现流量控制。
第五,发送窗口真正取决于 min(rwnd, cwnd)。
第六,MSS 指 TCP 数据部分最大长度,不含 TCP/IP 首部。
第七,TCP 的累计确认机制看起来像 GBN,但 TCP 不是简单的 GBN。
第八,三次握手是为了双方都确认彼此的发送、接收能力;四次挥手是因为 TCP 全双工,两个方向要分别关闭。
十四、最后把这部分压缩成一版考前速记
TCP 与 UDP 的报文区别,最核心就是一句:
UDP 面向报文,保留边界;TCP 面向字节流,不保留边界。
TCP 报文段标志位,常考 6 个:
URG、ACK、PSH、RST、SYN、FIN
其中最重要的是:
SYN:建立连接,占 1 个序号ACK:确认有效,纯 ACK 不占序号FIN:释放连接,占 1 个序号RST:异常复位
窗口字段表示:
接收方当前还能接收多少字节。
MSS 表示:
TCP 数据部分最大长度。
发送窗口取决于:
min(rwnd, cwnd)
三次握手记法:
SYN → SYN+ACK → ACK
四次挥手记法:
FIN → ACK → FIN → ACK
做一切握手挥手题,只抓三条规则:
- SYN 加 1
- FIN 加 1
- 纯 ACK 不加 1
- 数据按字节数推进
40Gb/s 下 32 位序号绕回时间:
2^32 B ÷ (40×10^9 ÷ 8) B/s ≈ 0.859 s
TCP 窗口和 GBN 的关系:
思想相似,都是滑动窗口;但 TCP 是端到端、按字节、兼顾流量控制和拥塞控制,不能简单等同于 GBN。
TCP 首部字段题、握手挥手题、窗口计算题的做题模板
前面把 TCP 的核心概念捋顺之后,真正到做题时,最需要的其实不是再背一遍定义,而是有一套能直接落笔、直接推数、直接排除错误选项的模板。TCP 这一章最典型的题,基本都可以归到三类:首部字段识别题、握手挥手分析题、窗口与确认计算题。这三类题看起来信息量很大,但真正上手时,判断路径其实很固定。
这一节就专门把这三类题的“固定做法”单独整理出来。后面复习时,只要把模板拿出来套,很多题就不会再乱。
一、TCP 首部字段题的做题模板
这类题最常见的出法,是给出一个场景,让判断应该使用哪个字段,或者直接问某个字段的作用,也可能把 TCP 和 UDP 的首部放在一起比较。看起来像记忆题,但真正想做稳,不能死记硬背,而是要按“这个字段解决什么问题”来分类。
做首部字段题时,我一般先不急着看选项,而是先问自己:题目问的到底是下面哪一类能力。
第一类,是“寻址和复用”。如果题目问的是“哪个进程和哪个进程通信”“区分同一主机上的不同应用进程”,那优先想到源端口和目的端口。
第二类,是“可靠传输和按序交付”。如果题目问的是“哪一部分保证有序”“哪一部分表示发送字节的位置”“确认到了哪里”,那优先想到序号和确认号。序号负责给字节编号,确认号负责说明下一次期望收到哪个字节。
第三类,是“连接建立和释放”。如果题目涉及三次握手、四次挥手、异常复位,那优先想到标志字段,尤其是 SYN、ACK、FIN、RST。
第四类,是“流量控制”。如果题目问接收方还能收多少、发送方最多还能发多少,优先想到窗口字段。
第五类,是“紧急数据和立即交付”。题目出现“紧急”“优先处理”,对应 URG 和紧急指针;题目出现“尽快提交应用层”,对应 PSH。
第六类,是“检错”。如果题目问首部中哪个字段用于差错检测,想到校验和。
也就是说,首部字段题不是一堆零散字段,而是按照功能一块一块记。这样做题时,先定位功能,再映射字段,速度会快很多。
二、TCP 首部字段题的速判表
为了后面复习更顺,我把最常见字段和考法压缩成一张表。考试时很多选项其实都能靠这张表快速排除。
| 字段 | 作用 | 题目里常见表述 |
|---|---|---|
| 源端口、目的端口 | 标识发送/接收进程 | 进程复用与分用、端到端逻辑通信 |
| 序号 seq | 本报文段数据部分第一个字节的编号 | 按字节编号、可靠传输、有序交付 |
| 确认号 ack | 期望收到对方的下一个字节编号 | 确认、累计确认、收到哪里为止 |
| 数据偏移 | TCP 首部长度 | 首部多长、数据从哪里开始 |
| 标志位 | 连接管理与状态控制 | SYN、ACK、FIN、RST、PSH、URG |
| 窗口 | 接收方当前可接收的数据量 | 流量控制、接收缓存剩余空间 |
| 校验和 | 检测差错 | 差错检测 |
| 紧急指针 | 紧急数据末尾位置 | URG、生效条件 |
这类题的常见陷阱有两个。
第一个陷阱,是把“窗口”误以为是发送方说了算。实际上 TCP 首部中的窗口字段,是接收方通告给发送方的,表示“我还能收多少”。
第二个陷阱,是把“确认号”理解成“已经收到的最后一个字节编号”。更准确的说法应该是:确认号表示期望收到的下一个字节编号。这两个说法看起来很像,但考试时如果表述严格,最好用后者。
三、遇到 TCP 首部字段题时,固定答题顺序怎么走
如果是选择题,我建议按下面的顺序过脑子。
先看题干关键词。
出现“连接建立”看 SYN。
出现“连接释放”看 FIN。
出现“确认”看 ACK 和确认号。
出现“流量控制”看窗口。
出现“复位”看 RST。
出现“紧急”看 URG。
出现“尽快交付”看 PSH。
如果是简答题,就不要只写字段名称,而应该写成“字段 + 作用 + 场景”三连。
比如问窗口字段的含义,最稳的写法不是只写“流量控制”,而是写:
“窗口字段由接收方填写,表示接收方当前还能接收的字节数,用于实现 TCP 的流量控制,限制发送方的发送速率。”
这种写法在考试里更容易拿满分,因为它不是只记住了名词,而是把逻辑关系写完整了。
三次握手和四次挥手题的做题模板
握手挥手题之所以让人头疼,根本原因不是步骤多,而是它同时考两个方向的序号变化。只要能把两个方向拆开,题目立刻就顺了。
我做这类题时,固定先做一件事:画两条序号线。
上面一条写客户端。
下面一条写服务器。
然后每来一个报文段,只检查四个信息:
- 谁发的
- 带了哪些标志位
- 有没有数据
- 对方应该确认到哪里
只要坚持这样做,哪怕题目把包数增加、把数据夹在中间,甚至加入 FIN、SYN、确认号混合,你都不会乱。
四、握手挥手题最核心的四条规则
这四条规则比背图更重要。几乎所有题都靠它们推出结果。
第一条,TCP 按字节编号。
序号不是报文段编号,而是字节编号。
第二条,SYN 和 FIN 各消耗一个序号。
只要报文段带 SYN 或 FIN,就会让本方向序号前进 1。
第三条,纯 ACK 不消耗序号。
如果只是确认,没有数据,也没有 SYN/FIN,那么 seq 本身不因为 ACK 而前进。
第四条,ack 表示“期望收到对方的下一个字节编号”。
也就是说,确认号 = 对方已正确发送到的最后位置 + 1。
这四条规则基本就是所有握手挥手题的底层算法。
五、三次握手题的标准模板
设客户端初始序号为 x,服务器初始序号为 y``。
第一步,客户端发起连接:
SYN=1, seq=x
因为 SYN 占一个序号,所以客户端后续序号从 x+1 开始。
第二步,服务器同意连接:
SYN=1, ACK=1, seq=y, ack=x+1
这里服务器确认了客户端的 SYN,所以确认号是 x+1。同时服务器自己也发了 SYN,因此服务器后续序号从 y+1 开始。
第三步,客户端确认:
ACK=1, seq=x+1, ack=y+1
因为这是纯 ACK,没有数据,没有 SYN/FIN,所以客户端的 seq 仍然是 x+1。
把这三步压缩成一个固定模板就是:
| 次数 | 方向 | 标志 | seq | ack |
|---|---|---|---|---|
| 1 | C → S | SYN | x | 无效 |
| 2 | S → C | SYN + ACK | y | x+1 |
| 3 | C → S | ACK | x+1 | y+1 |
以后只要题目一出现握手,直接把这个表默写出来,再按题目给的具体数字代进去。
六、四次挥手题的标准模板
设主动关闭方 A,初始关闭时该方向当前序号为 u;被动关闭方 B 当前序号为 v。
第一步,A 发 FIN:
FIN=1, seq=u
因为 FIN 占一个序号,所以 A 后续序号从 u+1 开始。
第二步,B 回 ACK:
ACK=1, seq=v, ack=u+1
注意这里通常是纯 ACK,所以 B 的 seq 不因为 ACK 改变。
第三步,B 自己也发 FIN:
FIN=1, ACK=1, seq=w, ack=u+1
如果 B 在第二次和第三次之间没有再发送数据,那么常直接有 w=v。
如果中间发过数据,那 w 就应等于发完那些数据后的新序号。
第四步,A 回 ACK:
ACK=1, seq=u+1, ack=w+1
这一步纯 ACK,不再额外消耗序号。
标准模板可以记成:
| 次数 | 方向 | 标志 | seq | ack |
|---|---|---|---|---|
| 1 | A → B | FIN | u | 旧值或无关 |
| 2 | B → A | ACK | v | u+1 |
| 3 | B → A | FIN + ACK | w | u+1 |
| 4 | A → B | ACK | u+1 | w+1 |
最容易错的地方,就是第二步和第三步里 B 的 seq。很多人会机械地把第二步 ACK 当成也占一个序号,这是错误的。纯 ACK 不占序号,所以如果中间没发数据,那么第二步和第三步的起始 seq 可以一样。
七、握手挥手题的万能推题步骤
以后碰到任何 TCP 握手挥手题,不管它是选择题还是大题,都可以用下面这个顺序。
先写清初始序号。
如果题目给了 ISN=100、seq=8000 之类,先在两条线各自标好。
然后按报文段顺序推进。
每看到一个报文段,就判断它是否包含:
- SYN
- FIN
- 数据
- 纯 ACK
接着更新本方向序号。
更新规则非常机械:
- 带 SYN:本方向 +1
- 带 FIN:本方向 +1
- 带数据:本方向 + 数据字节数
- 纯 ACK:本方向不变
最后更新对方确认号。
确认号始终写成:
ack = 期望收到的对方下一个字节编号
只要坚持“先更新发送方 seq,再更新接收方 ack”,这类题会非常稳。
窗口计算题的做题模板
TCP 窗口题比握手挥手更容易让人乱,因为它同时可能混着:
- 接收窗口 rwnd
- 拥塞窗口 cwnd
- 发送窗口
- 已发送未确认数据
- 确认号
- 可继续发送的数据量
如果没有模板,很容易每个词都认识,但整道题算不明白。
这类题最重要的是先把“窗口”拆成三个层次。
第一个层次,是接收方窗口 rwnd,它表示接收方还能收多少。
第二个层次,是拥塞窗口 cwnd,它表示当前网络允许发送方发多少。
第三个层次,是发送方实际可用窗口,它由前两者较小值决定,再扣除已发送未确认部分。
真正做题时,先固定记住一个总公式:
发送窗口上限 = min(rwnd, cwnd)
然后再记:
当前还能发送的数据量 = 发送窗口上限 - 已发送未确认的数据量
只要题目有窗口、有确认号、有已发未确认字节数,基本都是按这个思路算。
八、窗口题里几个名词的固定理解
为了防止后面一看到题干就被绕晕,最好先把几个词钉死。
“发送窗口”不是“已经发送出去的数据”,而是“允许发送但尚未确认的序号范围”。
“可用发送窗口”才是此刻还能继续发出去的部分。
“接收窗口”是接收方通告的剩余缓存空间。
“确认号”表示接收方目前按序收到了哪里,因此会决定发送窗口左边界能否右移。
也就是说,窗口题本质上是在问两件事:
第一,发送方理论上最多能占用多大窗口。
第二,在这个窗口里,已经用了多少,还剩多少可发。
九、窗口计算题的标准步骤
以后只要碰到 TCP 窗口题,建议固定按下面四步走。
第一步,找 rwnd 和 cwnd。
如果题目只给流量控制信息,没有拥塞控制,那就默认发送窗口主要看 rwnd。
如果两个都给,就先取最小值。
第二步,找“已发送未确认的数据量”。
这个量通常可以通过“已发送到哪个序号”“已确认到哪个序号”来求。
一般可写成:
已发送未确认 = 已发送最后一个字节编号 - 已确认到的前一个字节编号
如果题目直接给“还有多少未确认数据”,那更简单,直接用。
第三步,求当前还能发送的数据量。
公式就是:
还能发送 = min(rwnd, cwnd) - 已发送未确认
第四步,检查结果是否合理。
如果算出来是负数,说明此刻不能继续发;
如果算出来是 0,说明窗口已满;
如果大于 0,说明还可以继续发这么多字节。
这个模板适合绝大多数窗口选择题和计算题。
十、一个最常见的窗口题型,怎样套模板
比如题目说:
“发送方已发送 3000B,已确认 2000B,接收方通告窗口为 4000B,拥塞窗口为 5000B,问当前还能发送多少字节?”
这类题看起来字很多,但就是机械套公式。
先求发送窗口上限:
min(rwnd, cwnd) = min(4000, 5000) = 4000B
再求已发送未确认:
3000 - 2000 = 1000B
于是当前还能发送:
4000 - 1000 = 3000B
这就是答案。
这类题真正难的地方,不在算,而在分清“已发送”和“已确认”不是一回事。很多人会把已经确认的也算进占用窗口里,导致结果偏小。
十一、确认号与窗口结合题,最容易错在哪
这类题经常会问:
“接收方发送确认号 ack=5001,这表示什么?”
标准理解是:
这表示接收方已经按序收到了编号到 5000 为止的数据,下一次希望发送方从 5001 开始发送。
如果这时又给出接收窗口为 2000B,那么含义就是:
发送方接下来最多可以在 5001 开始的基础上,再占用 2000B 的接收窗口范围。
也就是说,确认号决定左边界,窗口大小决定右边界。
这个思想特别重要。以后看到“ack + 窗口”放在一起,就要想到:ack 定起点,window 定宽度。
十二、窗口题、握手题、首部字段题之间其实是连着的
很多人复习时把这三类题分开记,结果越记越散。实际上,它们之间是一条线。
首部字段题,解决的是“每个字段干什么”。
握手挥手题,考的是“seq、ack、SYN、FIN 如何联动”。
窗口计算题,考的是“ack、window、已发送数据如何联动”。
所以从根上说,这一章真正反复出现的核心只有四个量:
seqack- 标志位
- 窗口
做题时只要盯住这四个量,题干再长,也不会完全失控。
最后压缩成一版“考场速用模板”
TCP 首部字段题,先按功能分类:
- 端口:进程复用与分用
- seq:按字节编号
- ack:期望收到的下一个字节编号
- 标志位:连接建立、释放、复位、紧急、推送
- 窗口:接收方还能接收多少字节
- 校验和:差错检测
握手挥手题,只记四条规则:
- SYN 占 1 个序号
- FIN 占 1 个序号
- 纯 ACK 不占序号
- 数据按字节数推进序号
做题顺序固定为:
- 画两条序号线
- 看谁发
- 看有没有 SYN/FIN/数据
- 更新本方向 seq
- 用“期望收到的下一个字节编号”写 ack
窗口题只记两个公式:
发送窗口上限 = min(rwnd, cwnd)
当前还能发送 = min(rwnd, cwnd) - 已发送未确认
再配一句理解:
ack 决定左边界,window 决定窗口宽度。
TCP 这章最容易出错的典型陷阱清单
TCP 这一章很典型的一个问题是,单看每个知识点都不算难:三次握手能背,四次挥手也见过,窗口字段、确认号、MSS、序号这些概念也都认识。但一到做题,尤其是一道题里同时出现多个字段、多次交互、多个报文段的时候,就特别容易乱。很多错误并不是不会,而是“似懂非懂”,最后在细节处丢分。
这一节就专门把 TCP 里最容易出错的陷阱集中整理一下。后面复习时,光看这份“坑点清单”,往往比再看一遍概念更有用。
一、把 TCP 看成“面向报文”而不是“面向字节流”
这是 TCP 最根本、也最容易在后面反复连锁出错的地方。
很多人在刚学 TCP 时,会不自觉地把它想成“和 UDP 一样,也是一个一个数据包地传,只不过更可靠”。这个理解很容易导致后面很多题都做偏,因为 TCP 和 UDP 在传输对象上就不是一回事。
UDP 面向报文,应用层交给它一条报文,它基本就按这条报文发,接收时也按一条完整报文交给应用层,因此 UDP 保留报文边界。
TCP 面向字节流。应用层写入的是一串字节,TCP 只负责把这串字节可靠、按序送到对方,并不保留“这部分原来是一次 write 发的,那部分原来是另一次 write 发的”这种边界信息。一次应用层发送,可能被拆成多个报文段;多次应用层发送,也可能被合并进一个报文段。
这个地方一旦没想清楚,后面就容易犯两个典型错误。
第一个错误,是误以为 TCP 的序号对应“第几个报文段”。其实 TCP 的序号对应的是字节位置。
第二个错误,是看到“发送了一个 TCP 报文段”,就想当然地认为接收方也“一次收到一个完整单位”。实际上,接收方拿到的是字节流。
所以这一章最先要固定的一句话就是:
TCP 按字节编号,面向字节流;UDP 按报文组织,面向报文。
二、把 seq 当成“报文段编号”,而不是“字节编号”
这是 TCP 计算题里最常见的错误之一。
TCP 首部中的序号 seq,不是“这是第几个报文段”,而是:
本报文段数据部分第一个字节的编号。
这句话必须咬得很死,因为它会直接影响三类题:
第一类,是握手挥手题。
第二类,是带数据的确认号计算题。
第三类,是序号绕回题。
如果一个 TCP 报文段携带了 100B 数据,起始序号是 3001,那么它覆盖的数据范围就是 3001 到 3100,下一个报文段若紧接着发,序号就应从 3101 开始。
很多人错在把“发了一个报文段”就当成“序号 +1”。这在 TCP 中是错误的。只有两种特殊控制位会无论是否带数据都额外占一个序号,那就是 SYN 和 FIN。
所以序号推进的真正规则应该是:
- 发数据:序号加数据字节数
- 发 SYN:序号加 1
- 发 FIN:序号加 1
- 纯 ACK:序号不变
这个规则是 TCP 整章最核心的计算底座。
三、把 ack 理解成“收到了哪个编号”,而不是“下一个想收哪个编号”
确认号也是 TCP 里非常容易半懂不懂的点。
很多人在脑中会把它理解为“我收到了编号 1000 的数据,所以 ACK=1000”。这种理解在直觉上似乎也说得过去,但严格来说是不对的。
TCP 的 ack 的准确含义是:
接收方期望收到的下一个字节编号。
也就是说,如果 ack=1001,真正的含义不是“我只收到了 1001”,而是:
“到 1000 为止的字节我都已经按序收到了,下一次请从 1001 开始发。”
这也是为什么 TCP 使用累计确认。确认号一旦前进到某个位置,就表示在此之前的按序数据都已经确认了。
这个坑最容易在带数据的题里出问题。比如一个报文段起始 seq=500,数据长度 200B,那么它覆盖字节编号 500 到 699。如果对方正确收到并确认,那么返回的 ack 应该是 700,而不是 699,也不是 500。
所以可以把 ack 永远翻译成一句固定的话:
ACK 不是“收到哪”,而是“下次该从哪开始发”。
四、忘记 SYN 和 FIN 都会占用一个序号
这可以说是连接管理题里最致命的坑。
很多人知道数据会让序号前进,却忘了 SYN 和 FIN 也会各占一个序号。于是三次握手、四次挥手的 seq 和 ack 一算就错。
必须牢牢记住:
SYN 占 1 个序号,FIN 占 1 个序号,纯 ACK 不占序号。
这句话是做握手挥手题的第一铁律。
比如客户端发送:
SYN=1, seq=100
那么服务器确认时就必须写:
ack=101
因为 SYN 本身也占用了一个序号。
再比如 A 发送:
FIN=1, seq=800
那么 B 确认时应写:
ack=801
这和“带了 1B 数据所以 +1”在形式上很像,但来源不同。它不是数据长度,而是控制位 FIN 本身占了一个序号。
以后只要看到题目中出现 SYN 或 FIN,就应该立刻在脑中亮起一个提醒:
这里要 +1。
五、误以为“凡是 ACK 都会让 seq 加 1”
这通常是上一个坑的连带错误。
因为很多人背握手挥手时,只看到一连串“101、102、103”之类的数字变化,就误以为 ACK 也会推动 seq 前进。实际上,ACK 只是表示确认号字段有效,纯 ACK 本身不占用序号。
所以如果一个报文段只是:
ACK=1, seq=x, ack=y
而没有数据、没有 SYN、没有 FIN,那么这个报文段发完以后,发送方自己的序号仍然还是 x,不会因为“发了一个 ACK”就自动变成 x+1。
这个坑在四次挥手第二步和第四步最常见。
A 发 FIN 后,B 会先回一个 ACK,这个 ACK 如果没有带数据,那么 B 的 seq 不变。后面 B 再发 FIN 时,如果中间也没发数据,那么它发 FIN 时的 seq 和刚才那个 ACK 的 seq 往往是一样的。
很多题就专门利用这一点设陷阱,让人误把 ACK 当成也消耗序号,最后 seq 全线错位。
六、把 TCP 首部中的“窗口”误当成发送方自己的剩余发送能力
TCP 首部中的窗口字段很容易望文生义,以为“窗口”就是发送方能发多少。其实首部中的窗口字段,是接收方通告给发送方的窗口,也就是接收方当前还能接收多少字节。
换句话说,它不是发送方自言自语写进去的,而是接收方告诉对方:
“我这边接收缓存还有这么多空间,你最多还能往我这里压这么多字节。”
所以这个字段反映的是流量控制,约束的是发送方的发送速度,依据的是接收方的接收能力。
很多题里会问“窗口字段的含义是什么”,最稳的答法不是只写“TCP 的窗口大小”,而是写:
窗口字段表示接收方当前可接收的数据量,用于通知发送方进行流量控制。
这样表意最完整,也最不容易混成“发送方窗口”。
七、以为发送窗口只由 rwnd 决定,忘了还有 cwnd
如果只学了流量控制,很多人会觉得“窗口大小就是接收方通告窗口 rwnd”。这在只讨论流量控制的题目里不算错,但如果题目把拥塞控制也带进来,这个答案就不完整了。
TCP 发送方真正的发送窗口上限,应该取:
min(rwnd, cwnd)
其中:
rwnd反映接收方接收能力cwnd反映当前网络拥塞状况
所以发送方不是“想发多少就发多少”,也不是“只要接收方装得下就行”,而是既不能把接收方撑爆,也不能把网络打爆。
这个点经常在选择题里考表述的完整性。
如果题目只在讲流量控制,可以说发送窗口受接收方窗口影响;
如果题目明确把拥塞控制也纳入条件,就必须写完整:
发送窗口由接收窗口和拥塞窗口中较小者决定。
八、把“发送窗口大小”和“当前还能继续发送的数据量”混为一谈
这是窗口计算题里特别容易糊涂的地方。
“发送窗口大小”通常是说发送方理论上允许占用的窗口范围,常由 min(rwnd, cwnd) 决定。
但“当前还能继续发送多少”,并不等于这个窗口上限,因为窗口里可能已经装了一部分“已发送但未确认的数据”。
所以真正能再发多少,应该是:
当前可发送量 = min(rwnd, cwnd) - 已发送未确认数据量
这两个概念必须分开。
很多题里给出:
- 接收窗口 5000B
- 拥塞窗口 6000B
- 已发送未确认 2000B
然后问“当前还能发多少”。
这时答案不是 5000B,而是:
5000 - 2000 = 3000B
也就是说,窗口上限是 5000B,但里面已有 2000B 在“占位”,剩余可发只有 3000B。
所以看到窗口题,先别急着代公式,一定先问自己:
题目问的是“窗口上限”,还是“此刻还能发多少”。
九、看到确认号就只会机械相减,不理解“左边界”和“右边界”
窗口题里还有一个非常容易被忽视的本质:确认号和窗口字段其实是在一起定义发送空间。
确认号决定的是左边界,表示发送方已经确认到了哪里。
窗口字段决定的是右边界相对左边界还能向前开多宽。
所以如果接收方发来:
ack = 5001, window = 3000
这表示:
“5000 及以前的字节我都按序收到了,你接下来可以从 5001 开始继续发,并且最多还可以向前占用 3000B 的接收窗口空间。”
很多人做题时只会把窗口当作一个孤立数字看,没把它和确认号结合起来理解,这样一遇到图示题、区间题、发送窗口滑动题就容易蒙。
真正稳妥的理解是:
ack 定起点,window 定宽度。
十、把 MSS 和“整个 TCP 报文段长度”混淆
MSS 也是一个特别容易因为名字而想当然理解错的概念。
MSS 叫最大报文段长度,但它指的并不是“整个 TCP 报文段总长度”,而是:
TCP 报文段中数据部分的最大长度。
也就是说,MSS 不包括 TCP 首部,也不包括 IP 首部。
很多人看到“最大报文段长度”就本能觉得是整个段从头到尾的长度,这样一做 MTU 相关题就会出错。
最常见关系是:
MSS = MTU - IP首部长度 - TCP首部长度
例如以太网 MTU=1500B,IPv4 首部 20B,TCP 首部 20B,那么:
MSS = 1500 - 20 - 20 = 1460B
如果把 MSS 误当成整个 IP 数据报长度,或者误当成含首部的 TCP 总长度,结果都会错。
所以这个点最稳的记法就是:
MSS 只看 TCP 负载,不看首部。
十一、把 MSS 和 MTU 看成一回事
MSS 和 MTU 经常一起出现,因此很多人会顺手把它们混成一个概念。
但这两个量不在同一层。
MTU 是数据链路层概念,表示链路层帧中可承载的网络层数据的最大长度。
MSS 是传输层概念,表示 TCP 数据部分最大长度。
所以 MTU 更靠下,MSS 更靠上。
MSS 往往是为了适配 MTU,避免 IP 分片而确定的。
如果题目同时出现 MSS 和 MTU,要立刻反应过来:这不是同义替换,而是上下层之间的约束关系。
十二、误以为三次握手只是“打招呼”,没抓住其真实作用
如果只是死背“三次握手建立连接”,一到选择题问“为什么要三次,不是两次”,就容易答得很虚。
三次握手的本质,不是礼貌性打招呼,而是双方要确认:
- 我能发
- 我能收
- 你能发
- 你能收
换句话说,双方都要确认彼此收发能力正常,并完成初始序号同步。
所以三次握手第二步不是单纯回复一句“好”,而是服务器一边确认客户端的 SYN,一边把自己的 SYN 发出去;第三次握手则是客户端确认服务器的 SYN 已经收到。
如果这个逻辑没搞清,一到题目变形成“为什么两次不够”“为什么第三次必要”“失效连接请求报文段为何会出问题”时,就只能靠死记硬背,很容易答乱。
十三、误以为四次挥手是“规定动作”,没理解为什么通常需要四次
同样地,四次挥手如果只背流程,不理解原因,也很容易在题目变形时出问题。
四次挥手之所以通常是四次,不是因为 TCP 人为规定要四次,而是因为 TCP 是全双工,两个方向的关闭要分开进行。
A 发 FIN,只表示 A 这边没有数据要发了,即 A → B 这个方向准备关闭。
但这并不意味着 B → A 方向也立刻没数据了,所以 B 先回一个 ACK,等自己数据发送完毕后,再发 FIN。
这才形成了“FIN → ACK → FIN → ACK”的四步。
如果没抓住“两个方向独立关闭”这个本质,就会对很多变形题感到困惑,比如:
- 为什么不能总是三次挥手
- 为什么第二次和第三次有时能合并
- 为什么收到 FIN 后不一定马上也发 FIN
这些问题的答案,本质都来自“全双工、双向独立关闭”。
十四、看到四次挥手就忘了 TIME-WAIT 的意义
TIME-WAIT 是 TCP 里另一个高频但很容易背得空洞的点。
很多人只记得“主动关闭方最后要进入 TIME-WAIT,等待 2MSL”,但不知道为什么,于是一到选择题就容易在表述上被干扰。
TIME-WAIT 的主要作用通常可以归纳成两个。
第一,保证最后一个 ACK 能到达。
如果主动关闭方发出的最后 ACK 丢失,那么被动关闭方会重传 FIN。主动关闭方在 TIME-WAIT 状态下还能重发 ACK。
第二,防止旧连接中的延迟报文段影响后续新连接。
等待 2MSL,可以让网络中该连接残留的旧报文段基本失效。
如果这两个作用只记住一句模糊的“避免出错”,做题时就不牢。最好直接记成:
TIME-WAIT = 防最后 ACK 丢失 + 防旧报文干扰新连接。
十五、把“可靠传输”简单理解成“永远不会丢”
TCP 可靠,不等于物理上永远不丢包。
TCP 可靠的真正含义是:即使网络中可能丢失、失序、重复,TCP 也通过确认、重传、排序、校验等机制,尽量保证应用层最终拿到正确、按序、不重复的数据流。
这个点在概念判断题里很容易出“语言陷阱”。
比如题目说:
“TCP 可靠传输是指在传输过程中不会发生丢包。”
这种说法就是错的。
网络中当然可能丢包,TCP 的可靠性恰恰是建立在“可能丢、但能补救”的机制上。
所以以后看到“可靠”二字,不要把它理解成“绝不出错”,而要理解成“通过协议机制保证正确交付”。
十六、把 TCP 误当成数据链路层 GBN 的简单翻版
这个坑通常出现在学完数据链路层滑动窗口协议之后。
TCP 确实和 GBN、滑动窗口有相似性,比如都有序号、确认、窗口、超时重传、流水线发送,所以初学时会觉得“TCP 不就是更复杂一点的 GBN 吗”。
这种感觉不算完全错,但如果直接把它们等同起来,就会出问题。
TCP 和 GBN 至少有几个根本差异。
首先,层次不同。
GBN 是数据链路层协议思想,TCP 是传输层协议。
其次,编号单位不同。
GBN 通常按帧编号,TCP 按字节编号。
再次,TCP 除了可靠传输,还要处理流量控制和拥塞控制。
GBN 主要不是为了解决网络拥塞问题设计的。
最后,TCP 的确认与重传机制更复杂,实际实现中还可能有延迟确认、重复 ACK、快重传、SACK 等机制,不能简单套成“丢一个就全回退”。
所以更稳的表述应该是:
TCP 在确认和窗口思想上与滑动窗口协议相似,但它不是简单等同于 GBN。
十七、把“累计确认”理解成“只能确认一个报文段”
TCP 的累计确认机制也是一个很容易被表面化理解的点。
所谓累计确认,不是“每次只确认当前这个报文段”,而是:
确认号一旦推进到某个位置,就表示这个位置之前按序到达的数据都已经收到了。
例如 ack=5001,并不是只确认一个“5000 号包”,而是确认到 5000 为止的所有按序字节都已收到。
这个点如果没理解,一到判断题里出现“TCP 每收到一个报文段只确认该报文段”这种说法,就很容易误判。
十八、序号绕回题里忘记单位换算
这类题属于计算并不难,但很容易因为单位而翻车。
TCP 序号 32 位,序号空间是一圈 2^32。
关键是:这个 2^32 的单位是字节,不是 bit,也不是报文段个数。
如果题目再给链路速率,比如 10Gb/s、40Gb/s,那么必须先把速率从 bit/s 换成 B/s,再去计算:
时间 = 2^32 B ÷ 发送速率(B/s)
最容易错的地方通常有两个。
第一,忘记 TCP 按字节编号,把 2^32 误当成 bit。
第二,忘记 1B = 8bit,直接拿 bit/s 去除 byte 数。
所以以后只要看到“TCP 序号绕回”几个字,先在脑中自动补一句:
先统一单位,序号空间按字节算。
十九、把“建立连接需要三次”死记成绝对格式,不会处理变形题
很多学生背熟的是一个标准图:
SYN → SYN+ACK → ACK
但题目一旦变形,比如问:
- 第三次握手能不能携带数据
- 第二次握手为什么既有 SYN 又有 ACK
- 某个报文段丢失会发生什么
就容易不会了。
本质上,三次握手不是背“哪三个包”,而是背“双方各自要完成什么状态确认”。
所以一旦理解为:
- 客户端发起同步自己的初始序号
- 服务器确认客户端并同步自己的初始序号
- 客户端确认服务器的初始序号
很多变形题就顺了。
也就是说,握手题不要只记“图”,更要记“每一步各自在确认什么”。
二十、把题目里的“报文段”“确认号”“窗口”割裂开看
这是很多综合题做不出来的根本原因。
TCP 大题往往不是单独考某个点,而是把这些量放在一起:
- 某报文段的 seq
- 某报文段的数据长度
- 收到后的 ack
- 接收窗口大小
- 还能继续发送多少
- 下一次发送的 seq 应该是多少
如果复习时把这些内容孤立背诵,做题时就会觉得信息太多、太乱。
其实这些信息之间的关系非常固定:
seq 决定本段从哪开始。数据长度 决定本段发到哪。ack 决定对方确认到了哪。window 决定还能向前开多宽。
于是就能判断下一段从哪发、还能发多少。
所以 TCP 综合题真正的核心不是“记住很多知识点”,而是把几个量的关系连起来看。
最后压缩成一版“高频坑点速记清单”
如果考前只想快速扫一遍,下面这一版最适合直接过脑子。
TCP 面向字节流,不保留消息边界;UDP 面向报文,保留消息边界。
TCP 的 seq 按字节编号,不按报文段编号。
TCP 的 ack 表示“期望收到的下一个字节编号”。
SYN 占 1 个序号,FIN 占 1 个序号,纯 ACK 不占序号。
TCP 首部中的窗口字段是接收方通告窗口,不是发送方自报发送能力。
发送窗口上限取 min(rwnd, cwnd)。
当前还能发送的数据量,要再减去已发送未确认部分。
ack 决定左边界,window 决定宽度。
MSS 只指 TCP 数据部分最大长度,不含 TCP/IP 首部。
MSS 和 MTU 不是一回事,前者是传输层概念,后者是链路层概念。
三次握手的本质是双方确认彼此收发能力并同步初始序号。
四次挥手通常是因为 TCP 全双工,两个方向要分别关闭。
TIME-WAIT 的作用是保证最后 ACK 可重发,以及防旧报文干扰新连接。
TCP 可靠不等于永不丢包,而是通过协议机制保证最终正确交付。
TCP 与滑动窗口协议相似,但不能简单等同于 GBN。
序号绕回题一定先统一单位,按字节编号、按字节速率计算。



