ACK,SEQ,FIN,RTT
本文最后更新于3 天前,其中的信息可能已经过时,如有错误请发送邮件到184874483@qq.com

TCP 最容易混的几个点上:SYN/FIN 是否占序号seq 和 ack 到底各表示什么挥手时 FIN 到底意味着什么

一、先把最核心的规则捋顺:哪些东西会消耗序列号

TCP 的序列号本质上是给“字节流位置”编号的。通常有两类东西会占用一个序列号:

第一类是真正的数据字节。发送了多少字节数据,就消耗多少个序列号。

第二类是两个特殊控制位:SYNFIN。它们虽然不携带应用层数据,但都要各自占用 1 个序列号。

所以考试里一定要记住下面这三条:

  1. 普通 ACK 报文段如果不携带数据,那么不消耗序列号
  2. SYN=1 的报文段,即使不带数据,也消耗 1 个序列号
  3. FIN=1 的报文段,即使不带数据,也消耗 1 个序列号

这就是为什么大家常说:

数据消耗多少,序号就前进多少;SYN 和 FIN 各额外再加 1;纯 ACK 不加。


二、为什么 SYN 和 FIN 明明“不带数据”却还占一个序号

这不是随便规定的,而是 TCP 协议为了保证连接建立、连接释放也能被可靠确认。

可以把它理解成:

  • SYN:占一个“建立连接”的逻辑位置
  • FIN:占一个“结束发送”的逻辑位置

因此对方确认时,也必须把这一个位置确认掉,所以确认号会加 1。

这正是很多题目的陷阱来源:
不要把“是否带数据”和“是否占序号”画等号。
因为 SYNFIN 就是“不带数据但占序号”的典型例外。


三、第一道例题:如何根据 SYN 和第 4 次挥手求 A 发了多少字节数据

题目是:

主机 A 和 B 之间建立了一个 TCP 连接,A 向 B 发送的第一个 SYN 报文段中的序号值 seq = 211,数据传输结束,在释放连接时,A 向 B 发送的第 4 次挥手报文段的 seq = 985,则在本次通信过程中,A 向 B 总共发送了多少字节的数据?

这题的关键不是“第 4 次挥手”,而是要知道:

  • A 最开始发了一个 SYN
  • A 后面发送了若干数据
  • 如果 A 发的是第 4 次挥手报文段,说明 A 是最后发 ACK 的一方,也就是通常的主动关闭方 A:
    第 1 次挥手 A 发 FIN
    第 4 次挥手 A 再发一个纯 ACK

这里最关键的一点是:

第 4 次挥手是纯 ACK,不消耗序列号。
所以第 4 次挥手的 seq,实际上等于 A 在发送完 FIN 之后“下一个可用序列号”。

分步推

A 发的第一个 SYN:

  • seq = 211
  • 由于 SYN 占 1 个序列号,所以之后 A 的下一个序号变成 212

设 A 总共发送了 x 字节数据,那么数据发完后:

  • 序号前进到 212 + x

然后 A 发送第 1 次挥手的 FIN,FIN 还要再占 1 个序列号,所以发完 FIN 以后:

  • 下一个序号变成 213 + x

而第 4 次挥手是纯 ACK,不消耗序号,因此它的 seq 就应该是:

213 + x = 985

解得:

x = 985 - 213 = 772

结论

A 向 B 总共发送了 772B 的数据。

这类题的通用模板

只要题目从“初始 SYN 的 seq”跳到“后面某个 ACK/FIN 的 seq”,就按下面的式子想:

后面的 seq = 初始 SYN 的 seq + 1 + 数据字节数 + 是否发过 FIN

这里“是否发过 FIN”如果发过,就再加 1。

本题里正好是:

985 = 211 + 1 + 数据字节数 + 1

所以数据字节数就是:

985 - 211 - 2 = 772

易错点

最容易错成 773 或 774,原因一般有两个:

第一种错法:忘了 SYN 占 1。
第二种错法:忘了 FIN 也占 1。
第三种错法:误以为第 4 次挥手那个 ACK 也要占 1,其实纯 ACK 不占。


四、seq 和 ack 到底是什么关系

你提到一句非常关键的话:

同一个报文段中,seq 和 ack 没有任何联系

这个说法在做题意义上,基本可以认为是对的。

1)seq 表示什么

seq 表示:本报文段数据部分的第一个字节的序号

如果本报文段不带数据,但带 SYN 或 FIN,那么它表示的就是这个 SYN 或 FIN 占用的那个序号位置。

所以 seq 看的是“我这边发出去的内容,从哪一个编号开始”。

2)ack 表示什么

ack 表示:我期望收到对方下一个字节的序号

换句话说,ack = 已经正确收到对方的最后一个字节序号 + 1

所以 ack 看的是“我已经收到了你哪儿,你接下来该从哪儿继续发”。

3)为什么说同一个报文段中的 seq 和 ack 没直接关系

因为:

  • seq 是描述自己发出的数据
  • ack 是描述自己已收到对方的数据

二者分别对应两个方向的数据流。

TCP 是全双工的,A→B 和 B→A 的字节流编号是各自独立的。
所以一个报文里的 seqack,本质上是在说两件不同的事。

这正是考研题喜欢考的点:
不要把某个报文的 seq 和 ack 当成一个公式互相去推。

真正能推的是:

  • 对方回复的 ack 往往由我这个报文的 seq + 有效长度 推出来
  • 但同一个报文内部,seqack 不要求存在固定关系

五、第二道题:A 发给 B 的报文 seq=200,ack=201,数据部分 2B,B 的确认报文怎么求

题目:

A 和 B 之间建立了 TCP 连接,A 向 B 发送了一个报文段,其中序号字段 seq=200,确认序号字段 ack=201,数据部分有 2B,那么在 B 对该报文的确认报文段中……

这类题的核心就是求 B 回给 A 的确认信息。

先看 A 发出的报文

A 发给 B:

  • seq = 200
  • 数据长度 = 2B

这说明 A 这次发出去的数据字节序号是:

  • 第一个字节:200
  • 第二个字节:201

所以 B 收到后,下一次期望收到 A 的字节序号就是:

202

因此 B 发回的确认报文段中:

  • 确认号 ack = 202

那 B 的 seq 能不能确定

一般不能单独确定,除非题目还告诉了:

  • B 当前自己的发送序号是多少
  • 或者前面 B 已经发过多少数据
  • 或者是否只是纯 ACK 且初始状态已知

所以这题通常能确定的是:

  • ack = 202

而不是完整唯一确定 seq

为什么 A 报文里的 ack=201 对这一步没影响

因为 A 报文中的 ack=201 表示的是:

“A 已经收到 B 发来的序号到 200 为止的内容,期待 B 下一个从 201 开始发。”

这只是 A 对 B 的确认,和 B 对 A 这次 2B 数据的确认不是同一件事。

这正好再次说明:

一个报文里的 seq、ack 是两个方向上的信息。


六、第三类题:客户先发 FIN,后来收到服务器发来的 FIN,如何判断报文段 B

客户与服务器建立 TCP 连接,当连接断开时,客户先向服务器发送一个标志 FIN=1 的报文段 A,此报文段中 seq 值为 x,ack 值为 y。一段时间后,客户收到了服务器发来的一个标志 FIN=1 的报文段 B,则关于报文段 B 的说法中,

先看报文段 A

客户先发 FIN 报文段 A:

  • FIN=1
  • seq = x
  • ack = y

由于 FIN 要占一个序列号,所以服务器确认这个 FIN 时,应当确认到:

  • x + 1

因此,服务器之后发来的 FIN 报文段 B,通常会满足:

  • ack = x + 1

因为服务器已经收到了客户的 FIN。

那 B 的 seq 是多少

这个不能直接写成某个固定值,取决于服务器在这之前还有没有数据没发完。

分两种常见情况:

情况一:服务器没有额外数据要发

那服务器可能先回一个 ACK,再过一会儿再发 FIN。
此时服务器发 FIN 的 seq 就是它当前自己的下一个发送序号,具体数值取决于服务器之前发了多少数据。

情况二:服务器还有数据没发完

服务器可能先继续把剩余数据发完,最后再发 FIN。
那么这个 FIN 的 seq 就会更大。

所以通常能确定的是:

  • 报文段 B 的 ack = x + 1
  • 报文段 B 的 seq 不能仅凭题干唯一确定

这类题最容易错在哪里

最常见的错法是把服务器发来的 FIN 的 seq 也写成 x+1
这是错误的,因为:

  • x+1 是服务器对客户 FIN 的确认号
  • 服务器自己的 seq 走的是另一套编号

又回到了那句核心话:

seq 看自己,ack 看对方。


七、FIN 到底表示什么:是不是“一发 FIN 就整个连接断了”

你最后那道选择题本质是在考 FIN 的语义。

题目大意:

TCP 的通信双方,有一方发送了带有 FIN 标志的数据段后,表示
A. 将断开通信双方的 TCP 连接
B. 单方面释放连接,表示本方已经无数据发送,但可以接收对方的数据
C. 中止数据发送,双方都不能发送数据
D. 连接被重新建立

正确答案

B

为什么是 B

发送 FIN=1 的含义是:

“我这一边已经没有数据要发了,我的发送方向要关闭了。”

但 TCP 是全双工的,连接有两个方向:

  • A → B
  • B → A

所以一方发 FIN,只是表示本方发送方向关闭,并不代表另一方也立刻不能发了。

也就是说:

  • 发 FIN 的这一方:以后不能再发送数据
  • 但它仍然可以继续接收对方发送的数据

这就叫做半关闭单方向关闭

为什么不是 A

A 说“将断开通信双方的 TCP 连接”,这个说法太绝对了。
发出一个 FIN 以后,连接还没有完全断开,因为对方可能还有数据继续发。

真正完全断开,要等双方都完成各自方向的关闭,也就是通常的四次挥手走完。

为什么不是 C

C 说“双方都不能发送数据”,这明显不对。
一方发 FIN 后,对方仍然可以继续发数据。

为什么不是 D

D 更明显不对,FIN 是释放连接,不是重建连接。


八、把这几个知识点连成一个做题框架

做 TCP 首部字段、握手挥手、seq/ack 题时,我现在更建议按下面这个框架来判断。

第一步:先分清“谁给谁发”

TCP 是双向的,A→B 和 B→A 一定分开看。
只要题目一乱,先在草稿纸上标两个方向。

第二步:看 seq 是谁自己的编号

seq 永远看“本报文发送方”的发送字节流。

也就是:

  • A 发的报文,seq 看 A 自己发到哪儿了
  • B 发的报文,seq 看 B 自己发到哪儿了

第三步:看 ack 是对谁的确认

ack 永远看“本报文发送方已经收到了对方多少”。

也就是:

  • A 发的报文,ack 是 A 对 B 的确认
  • B 发的报文,ack 是 B 对 A 的确认

第四步:判断这次报文会不会让序号加长度

序号前进量 =

数据字节数 + SYN是否为1 + FIN是否为1

其中:

  • 纯 ACK:加 0
  • SYN:加 1
  • FIN:加 1
  • 带 n 字节数据:加 n

第五步:确认号怎么推

ack = 对方下一个应该发送的序号

也就是:

ack = 对方本次报文的 seq + 对方本次报文占用的序号长度

这里“占用的序号长度” again 就是:

数据长度 + SYN是否为1 + FIN是否为1


九、这几类题为什么总容易错

TCP 这一章最容易错,不是因为公式难,而是因为信息是“交叉的”。

同一个报文段里同时出现:

  • 本方的 seq
  • 本方对对方的 ack

于是脑子很容易把两个方向混在一起。

再加上 SYNFIN 这两个“不带数据却占序号”的特例,很多人就会在计算时少加 1 或多加 1。

所以做题时一定要强行养成两个习惯:

第一,分方向
永远把 A→B 和 B→A 分开记。

第二,先算占用长度
每遇到一个报文,先判断它占几个序号:

长度 = 数据字节数 + SYN?1:0 + FIN?1:0

只要这一步不乱,后面的 seqack 基本都能稳住。


TCP 里的 RTT 到底是什么,做题时怎么用

在 408 风格的传输层题目里,RTT 一般指往返时间,也就是一个报文从发送端到接收端,再从接收端返回发送端所经历的总时间。于是有一个最常用的换算:

单程传播时延 = RTT / 2

所以凡是涉及“三次握手、四次挥手、确认到达、最短释放时间”这类题,第一步通常就是把 RTT 先拆成两个 RTT/2 来看。

另外,TCP 题里最常配套考这几条规则:

第一,seq 表示本报文段数据部分第一个字节的序号
第二,ack 表示期望收到的下一个字节序号
第三,TCP 的确认通常是累计确认,中间缺了一段,即使后面的段到了,也不能越过去确认。
第四,发生超时时,按照考研常见模型处理为:

  • ssthresh = 当前cwnd / 2
  • cwnd = 1 MSS
  • 然后重新进入慢开始,达到门限后转入拥塞避免

第五,发送窗口大小不是只看拥塞窗口,还要看接收窗口:

发送窗口 = min(cwnd, rwnd)

下面按题目逐个拆。


第1题:客户主动断开后,服务器最短多久释放连接

题目大意是:

假设 TCP 客户与 TCP 服务器的通信已结束,端到端往返时间为 RTT。
t 时刻 TCP 客户请求断开连接,则从 t 时刻起,TCP 服务器释放该连接的最短时间是多少?

结论

t 时刻起,TCP 服务器最短在 1.5RTT 后释放连接

解题过程

这是标准的四次挥手题,而且问的是“服务器释放连接的最短时间”。

在最短情况下,可以认为服务器一收到客户端的 FIN,就立刻回复 ACK,并且自己也立即发送 FIN。

时间线如下:

第一步:客户端发送 FIN

客户端在 t 时刻发送 FIN。
该报文到达服务器,需要 RTT/2

所以服务器在:

t + RTT/2

收到客户端的断开请求。

第二步:服务器立刻回 ACK,并同时发自己的 FIN

若按最短情况处理,服务器在收到 FIN 的瞬间就可以发出 ACK,并且发出自己的 FIN。

客户端收到服务器发来的 FIN,也需要 RTT/2

所以客户端在:

t + RTT

收到服务器的 FIN。

第三步:客户端对服务器的 FIN 进行确认

客户端收到服务器 FIN 后,立刻发最后一个 ACK。
这个 ACK 再经过 RTT/2 到达服务器。

所以服务器在:

t + 1.5RTT

收到最终确认,正式释放连接。

为什么不是 RTT 或 2RTT

很多人会把“客户端进入 TIME_WAIT 等 2MSL”混进来。题目问的是服务器释放连接的最短时间,不是客户端彻底结束 TIME_WAIT 的时间。

所以答案看的是服务器进入 CLOSED 的时刻,即收到最后 ACK 的时刻,也就是:

1.5RTT


第2题:只收到第1个和第3个段时,确认号是多少

题目大意是:

甲向乙发送了 3 个连续的 TCP 段,分别包含 200B、300B、400B 的有效载荷,第 3 个段的序号为 1000
若乙仅正确接收到第 1 个和第 3 个段,则乙发送给甲的确认序号是多少?

结论

确认序号是:

700

解题过程

已知第 3 个段的 seq = 1000,它前面还有第 2 个段,长度为 300B

所以第 2 个段的起始序号应为:

1000 - 300 = 700

第 1 个段长度为 200B,所以第 1 个段起始序号为:

700 - 200 = 500

于是三个段分别是:

  • 第 1 段:seq = 500,长度 200B
  • 第 2 段:seq = 700,长度 300B
  • 第 3 段:seq = 1000,长度 400B

现在乙只收到了第 1 个和第 3 个,但第 2 个段丢了

TCP 采用累计确认,确认号永远指向“当前按序收到的最后一个字节之后的那个字节”。

乙虽然收到了第 3 段,但因为第 2 段没到,数据不连续,所以只能确认到第 1 段末尾之后。

第 1 段覆盖的字节范围是:

500 ~ 699

因此下一个期望收到的字节序号是:

700

所以确认号为:

ack = 700

这类题的核心陷阱

最容易错在一句话:后面的段到了,不代表确认号就能往后跳

TCP 的确认不是“我看见谁就确认谁”,而是“我按序连续收到了哪里”。


第3题:cwnd=34KB 时超时,4RTT 后窗口多大

题目大意是:

MSS 为 1KB,当拥塞窗口为 34KB 时发生了超时事件。
若在接下来的 4RTT 内报文段传输都成功,则当这些报文段均得到确认后,拥塞窗口大小是多少?

结论

拥塞窗口大小为:

16KB

解题过程

先处理超时:

  • 原来 cwnd = 34KB
  • 超时后,ssthresh = 34 / 2 = 17KB
  • cwnd = 1KB

接下来 4 个 RTT 内都成功,所以先走慢开始。

第1个 RTT 后

cwnd: 1 → 2

第2个 RTT 后

cwnd: 2 → 4

第3个 RTT 后

cwnd: 4 → 8

第4个 RTT 后

cwnd: 8 → 16

此时还没有达到门限 17KB,因此仍处于慢开始阶段。

所以 4RTT 结束后:

cwnd = 16KB

为什么不是 17KB 或更大

因为慢开始是按 RTT 近似看作“翻倍”,4 个 RTT 后正好是:

1, 2, 4, 8, 16

还没到 17,所以不会切到拥塞避免。


第4题:超时后经过 10RTT,发送窗口多大

题目大意是:

甲向乙发起 TCP 连接,MSS 为 1KB,乙每收到一个数据段都会发出一个接收窗口为 10KB 的确认段。
若甲在 t 时刻发生超时,此时拥塞窗口为 16KB
则从 t 时刻起,在不再发生超时的情况下,经过 10RTT 后,甲的发送窗口大小是多少?

结论

发送窗口大小为:

10KB

解题过程

这题不能只算 cwnd,最后要取:

发送窗口 = min(cwnd, rwnd)

第一步:超时后的参数变化

超时前 cwnd = 16KB

所以:

  • ssthresh = 16 / 2 = 8KB
  • cwnd = 1KB

第二步:10RTT 内窗口增长

先慢开始,到 8KB 为止;之后拥塞避免,每 RTT 加 1KB。

窗口变化过程如下:

  • 第1RTT 后:1 → 2
  • 第2RTT 后:2 → 4
  • 第3RTT 后:4 → 8
  • 第4RTT 后:8 → 9
  • 第5RTT 后:9 → 10
  • 第6RTT 后:10 → 11
  • 第7RTT 后:11 → 12
  • 第8RTT 后:12 → 13
  • 第9RTT 后:13 → 14
  • 第10RTT 后:14 → 15

所以 10RTT 后:

cwnd = 15KB

第三步:结合接收窗口 rwnd

题目给出乙的接收窗口始终是:

rwnd = 10KB

因此最终发送窗口:

min(15KB, 10KB) = 10KB

这题最容易错在哪

最常见错误是只算出了 cwnd = 15KB,然后直接把它当答案。
但题目问的是发送窗口,不是拥塞窗口。

发送窗口一定要再和接收窗口比较一次:

发送窗口 = min(cwnd, rwnd)


第5题:门限初始为8,cwnd到12时超时,第13次传输窗口多大

题目大意是:

TCP 的慢开始门限初始为 8(单位为报文段),当拥塞窗口上升到 12 时发生超时,TCP 开始慢开始和拥塞避免,则第 13 次传输时拥塞窗口大小是多少?

这里题干里的“发生短时”大概率就是“发生超时”。

结论

按考研常见简化模型,第 13 次传输时拥塞窗口大小为 7

解题过程

初始阶段

初始门限:

ssthresh = 8

默认开始时:

cwnd = 1

于是前几次传输轮次的窗口变化为:

  • 第1次:1
  • 第2次:2
  • 第3次:4
  • 第4次:8

到达门限后进入拥塞避免,每次加 1:

  • 第5次:9
  • 第6次:10
  • 第7次:11
  • 第8次:12

此时发生超时。

发生超时后

按照考研标准做法:

  • ssthresh = 12 / 2 = 6
  • cwnd = 1

然后重新慢开始:

  • 第9次:1
  • 第10次:2
  • 第11次:4
  • 第12次:6

达到门限后进入拥塞避免:

  • 第13次:7

所以答案为:

7

为什么有时会看到别的答案

这是因为严格工程实现里,慢开始按 ACK 增长,可能出现“不正好卡在 6”这种情况;但在考研题里,通常都按轮次模型门限整齐切换来算,也就是把过程写成:

1 → 2 → 4 → 8 → 9 → 10 → 11 → 12 → 超时 → 1 → 2 → 4 → 6 → 7

所以这道题的标准考试答案一般取 7


这 5 道题背后的统一做题模板

这几题表面上分别在考挥手、确认号、超时、拥塞控制、发送窗口,但实际上都可以归到一个模板里。

第一类:RTT / 挥手时间题

先画单程传播时延:

单程 = RTT/2

再按报文的发送顺序往下推,谁什么时候发,什么时候到,就能直接算出来。

这类题的关键不是背图,而是抓住:

  • 一次单向传播:RTT/2
  • 一来一回:RTT

第二类:seq / ack 题

固定两个原则:

  • seq:本段第一个字节编号
  • ack:期望收到的下一个字节编号

遇到“中间丢失、后面先到”的情况,一定记住:

TCP 采用累计确认,确认号不能跨过缺失的那一段。

第三类:超时后的 cwnd 题

直接套模板:

  • ssthresh = 原cwnd / 2
  • cwnd = 1 MSS
  • 然后慢开始
  • 到门限后改为拥塞避免

第四类:发送窗口题

最终别忘了还有接收方限制:

发送窗口 = min(cwnd, rwnd)

很多题故意把 rwnd 写出来,就是为了卡这一点。


这几类题最容易出错的点

这部分很值得单独记一下,因为确实是高频陷阱。

第一,把服务器释放连接时间和客户端 TIME_WAIT 混为一谈
服务器收到最后 ACK 就可以释放;客户端还可能继续等 2MSL,这不是一回事。

第二,把 ack 当成“已收到最后一个字节序号”
其实 ack 是“下一期待字节序号”。

第三,看到后续段到了,就把 ack 往后推
累计确认不允许这样做,中间断了就只能确认到断点。

第四,超时后忘记把 cwnd 重置为 1 MSS
很多人只记得门限减半,忘了超时的恢复动作更猛烈。

第五,把 cwnd 当成最终发送窗口
只要题里给了 rwnd,就要做 min(cwnd, rwnd)

第六,传输轮次题里把“窗口增长后的值”和“本轮发送时使用的值”搞混
这类题建议统一按“第 k 次传输时,cwnd 是多少”来列序列,别在脑中跳来跳去。


补充例题:TCP 中 RTT、慢开始、拥塞窗口、发送窗口的综合题

本质上还是围绕同一套规则在考,只是题干换了不同说法。先把这套规则再压一遍,后面每题就会很顺。

在 408 题里,若题目没有特别说明,默认按这种简化模型来做:

  • 连接建立成功后,初始 cwnd = 1 MSS
  • 慢开始阶段,每经过 1 个 RTT,cwnd 近似翻倍
  • 到达 ssthresh 后转入拥塞避免,每经过 1 个 RTT,cwnd 增加 1 MSS
  • 发送窗口 swnd = min(cwnd, rwnd)
  • 没有拥塞时,决定发送窗口上限的往往就是 rwnd
  • 出现 3 个冗余 ACK,一般按 TCP Reno 的快重传 + 快恢复 来做
  • 出现 超时,一般按 ssthresh = cwnd/2cwnd = 1 MSS 来做

1. 发送窗口第一次达到 20KB,需要多久

题目大意:

已建立 TCP 连接,MSS = 2KB,接收窗口始终为 20KBssthresh = 16KBRTT = 10ms,发送时延忽略,无拥塞。问甲的发送窗口第一次达到 20KB 经过多久。

结论

答案是:50ms(B)

解题过程

发送窗口:

swnd = min(cwnd, rwnd)

由于 rwnd = 20KB 恒定,所以只要看 cwnd 什么时候增长到 20KB 即可。

初始:

cwnd = 1 MSS = 2KB

又因为 ssthresh = 16KB,所以先慢开始,后拥塞避免。

按 RTT 演化:

  • 初始:cwnd = 2KB
  • 1RTT 后:4KB
  • 2RTT 后:8KB
  • 3RTT 后:16KB
  • 4RTT 后:18KB
  • 5RTT 后:20KB

每个 RTT 是 10ms,所以第一次达到 20KB 的时间为:

5 × 10ms = 50ms

易错点

最容易错成 40ms。错因在于把 16KB20KB 这一段还当成翻倍增长了。其实到达门限 16KB 后,就进入拥塞避免,每 RTT 只增加 1 MSS = 2KB


2. 慢开始阶段,本 RTT 发了 k 个段,下一个 RTT 发多少个段

题目大意:

某 TCP 连接正处于慢开始阶段,在某个 RTT 内发送了 k 个数据段。若仍然处于慢开始阶段,则下一个 RTT 内将发送多少个数据段。

结论

答案是:2k

解题过程

慢开始的核心特征就是:拥塞窗口按 RTT 近似指数增长

也就是说:

  • 这一轮能发 k 个段
  • 下一轮就能发 2k 个段

所以答案是:

2k

易错点

这个题非常基础,但很容易和拥塞避免混淆:

  • 慢开始:翻倍
  • 拥塞避免:每 RTT 加 1 个 MSS

只要看到题干明确写了“仍然保持在慢开始阶段”,那就是直接翻倍。


3. cwnd = 34KB 时收到 3 个冗余 ACK,4RTT 后窗口多大

题目大意:

在一个 TCP 连接中,MSS = 1KB,当 cwnd = 34KB 时收到了 3 个冗余 ACK。若接下来的 4RTT 内传输都成功,则这些报文段都被确认后,拥塞窗口大小是多少。

选项里有:21KB、20KB、16KB、8KB

结论

按考研里这类题的常规做法,答案是:21KB(D)

解题过程

这题和“超时”不一样。
题目明确说的是:收到 3 个冗余 ACK

这通常按 TCP Reno 的快重传 + 快恢复 来处理。

第一步:设置门限

ssthresh = 34 / 2 = 17KB

第二步:进入快恢复

收到 3 个冗余 ACK 后,Reno 一般令:

cwnd = ssthresh + 3 MSS = 17 + 3 = 20KB

这是因为那 3 个冗余 ACK 表示网络中仍有 3 个报文段离开了发送方并到达了接收方,只是有一个丢失了。

第三步:后续成功传输 4RTT

在这类考题里,后续通常按线性增长来处理。
收到对重传段的确认后,退出快恢复,进入拥塞避免,cwnd 回到 ssthresh = 17KB,然后每 RTT 增长 1KB
但很多 408 题目和选项设计,是直接把“3 个冗余 ACK 触发后的可发送窗口”视作后续增长起点,结合选项通常取 21KB

更稳妥的考场判断是:

  • 若题目是“超时” → 多半走 1 → 2 → 4 → 8 → 16
  • 若题目是“3 个冗余 ACK” → 多半考 Reno 快恢复,答案会落在 20KB21KB
  • 结合本题给的标准选项,常规答案取 21KB

这题为什么和“超时”那题答案不一样

因为它们触发的是两种不同机制:

  • 超时:说明拥塞更严重,cwnd 直接重置为 1 MSS
  • 3 个冗余 ACK:说明网络里还有数据在流动,更可能是个别报文丢失,因此不必降得那么狠

所以这题不会回到 1KB 重新慢开始,也就不会得到 16KB 那种答案。


4. 下一个 RTT 最多还能发送多少数据

题目大意:

A 和 B 建立 TCP 连接,MSS = 1KB。某时刻,ssthresh = 2KB,A 的 cwnd = 4KB
在接下来的 1RTT 内,A 向 B 发送了 4KB 数据并收到确认,确认报文中的窗口字段值为 2KB。问下一个 RTT 中,A 最多还能发送多少数据。

结论

答案是:2KB

解题过程

先看拥塞控制状态。

因为:

cwnd = 4KB > ssthresh = 2KB

所以此时已经处于拥塞避免阶段

在拥塞避免阶段,经过 1RTT 后:

cwnd = 4KB + 1KB = 5KB

但题目又给了确认报文中的窗口字段值:

rwnd = 2KB

因此发送窗口为:

swnd = min(cwnd, rwnd) = min(5KB, 2KB) = 2KB

所以下一个 RTT 中,A 最多发送:

2KB

易错点

最容易只看 cwnd,算出 5KB 就直接选。
但题干专门告诉了“确认报文中的窗口字段值为 2KB”,这就是在提醒:还要受接收窗口约束。


5. 发送方何时能发出第一个“完全窗口”24KB

题目大意:

无拥塞,RTT = 10ms,采用慢开始,rwnd = 24KBMSS = 2KB。问发送方能发送出第一个完全窗口,也就是发送窗口达到 24KB,需要的时间是多少。

结论

答案是:40ms

解题过程

仍然只看 cwnd 增长到什么时候不小于 24KB

初始:

cwnd = 1 MSS = 2KB

慢开始阶段每 RTT 翻倍:

  • 初始:2KB
  • 1RTT 后:4KB
  • 2RTT 后:8KB
  • 3RTT 后:16KB
  • 4RTT 后:32KB

此时:

swnd = min(cwnd, rwnd) = min(32KB, 24KB) = 24KB

所以到第 4RTT 末,发送窗口第一次达到 24KB

因为:

RTT = 10ms

所以所需时间:

4 × 10ms = 40ms

易错点

这题容易纠结“达到 24KB”还是“真正把 24KB 发完”。
408 常规做法是:发送窗口首次达到 24KB 的那个时刻 就算达成条件,也就是 40ms


这几道题背后的统一方法

做到这里,其实规律已经非常清楚了。

一类:问发送窗口什么时候达到某值

先算 cwnd 的增长,再和 rwnd 比较:

swnd = min(cwnd, rwnd)

rwnd 恒定,就基本等价于问 cwnd 什么时候长到那个值。
rwnd 变化,就必须两边一起看。

一类:问下一个 RTT 能发多少

核心不是只看 cwnd,而是看:

swnd = min(cwnd, rwnd)

题目只要给了确认报文中的窗口值,十有八九就是要卡这个点。

一类:问慢开始阶段下一轮发多少段

这类是最直接的:

  • 本轮 k
  • 下轮 2k

一类:问冗余 ACK 与超时的区别

一定要分清:

  • 超时:降得狠,cwnd 回到 1 MSS
  • 3 个冗余 ACK:一般按 Reno,走快重传、快恢复,不会直接掉回 1

TCP 中 RTT、seq/ack、cwnd、rwnd、慢开始、快恢复题型总表

最近把 TCP 这一块反复做题之后,会发现很多题虽然表面长得不一样,但真正反复在考的东西其实并不多。核心无非就是三条主线:第一条是报文段里的 seqack 怎么理解、怎么计算;第二条是连接建立与释放过程中,时间、RTT、报文往返怎么推;第三条是拥塞控制与流量控制,也就是 cwndrwnd、发送窗口、慢开始、拥塞避免、快重传、快恢复这些概念如何串起来。只要这三条主线能理顺,绝大多数 TCP 计算题都能落到固定模板里去做。

这份笔记就专门把这一块整理成一个可以直接复习和刷题时翻看的总表,不只讲“是什么”,更强调“怎么考”“怎么做”“哪里容易错”。


一、先把最核心的几个量彻底分清

TCP 题目最容易乱,其实不是因为公式复杂,而是因为变量太多,看起来都很像。所以最开始一定要先把几个最核心的量分清。

1. RTT

RTT 是往返时间,也就是一个报文从发送端出发,到接收端,再从接收端返回发送端所经历的总时间。

在做题时,最常用的就是:

单程传播时延 = RTT / 2

所以只要题目出现“某时刻发送 FIN”“某时刻收到 ACK”“最短经过多久到达对端”之类的时间题,第一反应就是把一个 RTT 拆成两个 RTT/2

2. seq

seq 指的是:本 TCP 报文段中数据部分第一个字节的序号

注意这里是“数据部分第一个字节”的编号,不是“第几个报文段”,也不是“这个报文段总共发了多少字节”。

所以如果一个段的 seq = 1000,而它携带 400B 数据,那它覆盖的字节范围就是:

1000 ~ 1399

下一段如果紧跟在它后面,那么下一段的起始序号就是:

1400

3. ack

ack 指的是:接收方下一步期望收到的字节序号

这个定义很关键。它不是“已经收到的最后一个字节序号”,而是“还想收到的下一个字节序号”。

所以如果某一方已经按序收到了 1 ~ 500 号字节,那么它返回的确认号应该是:

ack = 501

4. rwnd

rwnd 是接收窗口,属于流量控制,本质上反映的是接收方缓存还有多少空间。

接收方通过 TCP 首部里的“窗口字段”告诉发送方:我还能再收多少。

所以 rwnd 体现的是接收方的处理/缓存能力限制

5. cwnd

cwnd 是拥塞窗口,属于拥塞控制,是发送方自己根据网络拥塞状况估计出来的“现在我最多该发多少”。

所以 cwnd 体现的是网络承受能力限制

6. 发送窗口 swnd

真正决定“当前这一轮最多能发多少”的,不是单独看 cwnd,也不是单独看 rwnd,而是看两者中更小的那个:

发送窗口 swnd = min(cwnd, rwnd)

这一句是几乎所有 TCP 窗口计算题的总开关。题目只要同时给了 cwnd 和窗口字段,最后就一定不能忘记比较一次。


二、seq 和 ack 题的做题主线

TCP 的 seq/ack 题,在考研题里非常高频。它的本质其实就两条:

第一,seq 是数据起点;
第二,ack 是下一个想收到的数据编号。

但真正做题时,最容易错的点在于:TCP 的确认通常是累计确认。这句话如果没理解透,题目就会反复做错。

1. 累计确认是什么意思

所谓累计确认,就是接收方只能确认“已经按序连续收到”的那一部分。

如果中间少了一段,即使后面的报文段先到了,确认号也不能直接跳过去。

例如,发送方连续发送了三个段:

  • 第 1 段:200B
  • 第 2 段:300B
  • 第 3 段:400B

已知第 3 段的 seq = 1000,那么:

  • 第 2 段的 seq = 1000 - 300 = 700
  • 第 1 段的 seq = 700 - 200 = 500

于是三个段就是:

  • 第 1 段:seq = 500,覆盖 500 ~ 699
  • 第 2 段:seq = 700,覆盖 700 ~ 999
  • 第 3 段:seq = 1000,覆盖 1000 ~ 1399

如果接收方只收到了第 1 段和第 3 段,没有收到第 2 段,那么它虽然“看见”了第 3 段,但因为中间断了,仍然只能确认到第 1 段结束处,所以确认号是:

ack = 700

这类题最容易错成 1400,原因就是把 TCP 的确认理解成“见到什么确认什么”。其实不是,TCP 默认是累计确认,缺口不补上,确认号就过不去。

2. SYN 和 FIN 为什么会消耗一个序号

seq 题时,还有一个特别高频的细节:SYNFIN 都会各自消耗一个序号,即使它们本身不携带普通数据。

也就是说:

  • 发送一个 SYN,序号会占掉 1
  • 发送一个 FIN,序号也会占掉 1
  • 普通 ACK 如果不携带数据,则不消耗序号
  • 普通数据段消耗的序号数 = 数据字节数

所以凡是三次握手、四次挥手、求某段 seqack 的题,一定要注意:SYNFIN 要不要算进去。很多题就是专门卡这 1 个序号。


三、RTT 与连接建立 / 释放时间题怎么做

这类题本质上是“时间轴题”。真正解法不是死背流程图,而是按报文发送顺序,把它们一个个放到时间线上。

1. 建立连接的时间分析思路

三次握手的最基本过程是:

  • 客户端发 SYN
  • 服务器回 SYN + ACK
  • 客户端再回 ACK

如果只考虑传播时延,忽略发送时延,并且题目问“什么时候建立成功”,通常要注意:

  • 客户端视角:收到服务器的 SYN+ACK 并发出最后 ACK 后,可以认为连接建立完成
  • 服务器视角:收到客户端最后一个 ACK 后,才知道连接真正建立完成

因此不同问法,最后时间可能不同。

2. 释放连接的时间分析思路

四次挥手的标准流程是:

  • 主动关闭方发 FIN
  • 被动关闭方回 ACK
  • 被动关闭方再发 FIN
  • 主动关闭方回最后 ACK

例如有这样一题:

已知 RTT,客户端在 t 时刻请求断开连接,问从 t 时刻起服务器最短多久释放连接。

最短情况是服务器一收到客户端的 FIN,就立刻回 ACK,并且立刻也发出自己的 FIN。那么时间线就是:

  • t:客户端发 FIN
  • t + RTT/2:服务器收到 FIN
  • t + RTT:客户端收到服务器的 FIN
  • t + 1.5RTT:服务器收到客户端对该 FIN 的最后 ACK

因此服务器最短释放连接时间是:

1.5RTT

这类题最容易混淆的点在于,把“服务器释放连接时间”和“客户端进入 TIME_WAIT 继续等待 2MSL”混成一回事。题目问谁,就只看谁的状态变化,不要把另一端的等待时间强行带进来。


四、cwnd、rwnd、发送窗口这三个量怎么串起来

这部分是 TCP 最容易混淆的地方。很多题做不出来,不是不会算,而是根本没分清“谁在管什么”。

1. rwnd:接收方说“我还能收多少”

rwnd 由接收方根据缓存剩余空间给出,反映的是接收方“吃不吃得下”。

如果接收方缓存很小,或者接收方虽然收到数据但迟迟不取走,那么 rwnd 就会越来越小,最后可能把发送窗口卡死。

2. cwnd:发送方根据网络状况说“我最多该发多少”

cwnd 是发送方根据拥塞控制算法动态调整的结果。网络状况好,cwnd 增大;一旦发生拥塞,cwnd 就要缩小。

3. 最终发多少:看更小的那个

真正能发多少要看:

发送窗口 = min(cwnd, rwnd)

所以一个很常见的出题方式是:

  • 先让 cwnd 看起来很大
  • 再在 ACK 报文里给一个很小的窗口字段
  • 问你“下一个 RTT 最多能发多少”

这种题如果只顾着算 cwnd,就一定会错。

例如:

已知 ssthresh = 2KBcwnd = 4KB,经过一个 RTT 后收到了确认,而确认报文中的窗口字段值是 2KB。问下一 RTT 最多发送多少。

因为 cwnd = 4KB > ssthresh = 2KB,所以现在处于拥塞避免阶段,经过 1RTT 后:

cwnd = 5KB

但接收方只给出:

rwnd = 2KB

所以真正能发的是:

swnd = min(5KB, 2KB) = 2KB

答案就不是 5KB,而是 2KB


五、慢开始和拥塞避免是怎么算的

这部分在题目里几乎是必考,而且是所有窗口计算题的基础。

1. 考研题中的默认简化模型

如果题目没有特别说明,一般按这种模型做:

  • 连接建立成功后,初始 cwnd = 1 MSS
  • cwnd < ssthresh 时,处于慢开始
  • 慢开始阶段,每经过 1 个 RTT,cwnd 近似翻倍
  • cwnd >= ssthresh 时,转入拥塞避免
  • 拥塞避免阶段,每经过 1 个 RTT,cwnd 增加 1 MSS

这里的“按 RTT 翻倍”“按 RTT 加 1”是考研做题模型,足够应付绝大多数选择题和计算题。

2. 一个最典型的增长例子

例如:

  • MSS = 2KB
  • ssthresh = 16KB
  • rwnd = 20KB
  • RTT = 10ms

问发送窗口第一次达到 20KB 需要多久。

初始:

cwnd = 1 MSS = 2KB

于是窗口演化为:

  • 初始:2KB
  • 1RTT 后:4KB
  • 2RTT 后:8KB
  • 3RTT 后:16KB
  • 4RTT 后:18KB
  • 5RTT 后:20KB

所以第一次达到 20KB 需要:

5RTT = 50ms

这类题最容易错成 40ms,错因就是忘了到达门限之后已经不再翻倍,而是改成线性增长。

3. 慢开始阶段某一轮发了 k 个段,下一轮发多少

如果题目明确说仍在慢开始阶段,那么答案非常直接:

  • 这一 RTT 发了 k 个段
  • 下一 RTT 发 2k 个段

因为慢开始本质就是窗口指数增长。


六、超时和 3 个冗余 ACK 的处理一定要分开

这一点是 TCP 拥塞控制题里最关键的分水岭。很多题目故意把“超时”和“3 个冗余 ACK”放在一起考,就是想看是否真的分清了两种情况。

1. 超时的处理

如果发生超时,说明网络拥塞比较严重。考研里通常按下面处理:

  • ssthresh = 当前cwnd / 2
  • cwnd = 1 MSS
  • 重新进入慢开始

例如:

MSS = 1KB,当 cwnd = 34KB 时发生超时,接下来 4RTT 都成功,问 4RTT 后 cwnd 多大。

先处理超时:

  • ssthresh = 34 / 2 = 17KB
  • cwnd = 1KB

然后慢开始:

  • 1RTT 后:2KB
  • 2RTT 后:4KB
  • 3RTT 后:8KB
  • 4RTT 后:16KB

所以答案是:

16KB

2. 3 个冗余 ACK 的处理

如果收到 3 个冗余 ACK,说明网络还没有完全阻塞,更可能是个别报文段丢失。这时一般按 TCP Reno 的快重传 + 快恢复 处理。

考研常见简化理解是:

  • ssthresh = 当前cwnd / 2
  • 不像超时那样把 cwnd 直接打回 1 MSS
  • 之后按快恢复、再转入拥塞避免去增长

例如:

MSS = 1KBcwnd = 34KB 时收到 3 个冗余 ACK`,接下来 4RTT 都成功,问最后窗口多大。

这类题如果按 Reno 的套路来做,常见标准答案取:

21KB

也就是说,这题和“超时”那题的答案不会一样。出题人就是在考:是否知道“冗余 ACK”和“超时”的处理策略不同。

3. 做题时的快速识别法

看到“超时”两个字,第一反应就是:

cwnd -> 1 MSS

看到“3 个冗余 ACK”,第一反应就是:

“不回到 1,按快重传 / 快恢复处理”

这个分界一定要养成条件反射。


七、发送窗口达到某个值的题怎么做

这类题是考研里特别喜欢出的,因为它能同时考慢开始、拥塞避免、RTT 和接收窗口。

做法一般是两步。

第一步,先推 cwnd 的变化;
第二步,再和 rwnd 比较,看真正的发送窗口 swnd 是多少。

1. 接收窗口恒定时

如果接收方缓存总是及时清空,rwnd 恒定,那么题目就基本等价于在问:cwnd 什么时候长到那个值。

例如:

  • rwnd = 24KB
  • MSS = 2KB
  • RTT = 10ms
  • 无拥塞,只采用慢开始

问发送方何时能发出第一个完全窗口,也就是发送窗口达到 24KB

初始:

cwnd = 2KB

慢开始:

  • 初始:2KB
  • 1RTT 后:4KB
  • 2RTT 后:8KB
  • 3RTT 后:16KB
  • 4RTT 后:32KB

这时:

swnd = min(32KB, 24KB) = 24KB

所以第一次达到 24KB 的时间是:

40ms

2. 接收窗口不断缩小时

如果接收方缓存只进不出,那么 rwnd 会越来越小。这类题看起来更乱,但实际上只要列一张表就很清楚。

例如:

  • MSS = 1KB
  • RTT = 3ms
  • 接收缓存总大小 16KB
  • 接收方缓存只有数据存入,没有数据取出
  • 无拥塞

连接建立成功后,按考研默认,初始 cwnd = 1KB

窗口演化表如下:

时刻已累计收到数据剩余接收窗口 rwnd拥塞窗口 cwnd发送窗口 swnd
建立后立即0KB16KB1KB1KB
3ms1KB15KB2KB2KB
6ms3KB13KB4KB4KB
9ms7KB9KB8KB8KB
12ms15KB1KB16KB1KB

从这张表就能一眼看出:

  • 发送窗口第一次达到 4KB:在 6ms,此时接收方可用空间 13KB
  • 发送窗口第一次达到 8KB:在 9ms,此时接收方可用空间 9KB

这种题如果不列表,脑子里很容易乱;一旦列表,就几乎不会错。


八、RTT、窗口、序号题的统一做题模板

做 TCP 题时,真正有用的不是背很多零碎结论,而是形成固定模板。只要看到题目,就知道先从哪几步下手。

1. 如果题目在问 seq / ack

第一步,先判断 seq 是哪个段“数据部分第一个字节”的编号。
第二步,根据数据长度推出各段覆盖范围。
第三步,若有丢失、乱序,优先按“累计确认”处理。
第四步,确认是否有 SYNFIN,它们是否要各占 1 个序号。

2. 如果题目在问挥手、建连时间

第一步,先把 RTT 拆成 RTT/2
第二步,在纸上画时间线。
第三步,按“谁发出、谁收到、再由谁返回”的顺序逐个推。
第四步,只回答题目问的那一端,不要把另一端的等待状态乱带进去。

3. 如果题目在问 cwnd 变化

先看题目给的是哪种触发条件:

  • 若是“无拥塞 / 正常增长” → 慢开始 + 拥塞避免
  • 若是“超时” → ssthresh = cwnd/2cwnd = 1 MSS
  • 若是“3 个冗余 ACK” → 快重传 / 快恢复思路

4. 如果题目在问真正能发多少

最后一步统一做:

swnd = min(cwnd, rwnd)

只要题目给了接收窗口,就必须做这一步。


九、最容易出错的典型陷阱清单

TCP 这一章题目并不难,但坑很多,尤其是选择题,经常就是拿这些习惯性错误来设陷阱。

1. 把 ack 当成“最后收到的字节号”

这是最常见错误。
正确理解应是:

ack = 下一个期望收到的字节序号

2. 忘记累计确认不能跨过缺口

后面的段即使收到了,只要中间丢了一段,确认号就不能跳过去。

3. 忘记 SYN 和 FIN 也要消耗一个序号

这在握手、挥手题里非常高频。普通不带数据的 ACK 不消耗序号,但 SYNFIN 会各自占掉 1 个序号。

4. 把 cwnd 直接当成发送窗口

只有在 rwnd 足够大时,才有可能“发送窗口 = cwnd”。
一般情况下必须比较:

swnd = min(cwnd, rwnd)

5. 到了 ssthresh 之后还继续按翻倍算

这是慢开始 / 拥塞避免混淆导致的典型错误。
到达门限之后,通常就该改成每 RTT 增加 1 MSS

6. 把 3 个冗余 ACK 和超时当成同一种情况

这两个的处理强度不一样:

  • 超时:说明更严重,cwnd 回到 1 MSS
  • 3 个冗余 ACK:一般不打回 1 MSS

7. 时间题里把 TIME_WAIT 硬带进服务器释放时间

问服务器什么时候释放,就只看服务器什么时候收到最后 ACK。
客户端之后还要不要等 2MSL,那是另一回事。


十、把前面做过的典型例题统一归类

为了后续复习方便,可以把前面几道题按题型直接归类记忆。

1. RTT / 挥手时间题

典型题:客户端在 t 时刻请求断开连接,服务器最短多久释放连接。

结论:
1.5RTT

关键词:
FINACK、最后确认、单程 RTT/2

2. seq / ack 题

典型题:3 个连续段长度分别为 200B、300B、400B,第 3 段 seq = 1000,只收到第 1 段和第 3 段,问确认号。

结论:
ack = 700

关键词:
累计确认、缺口不能越过、确认到第一个丢失字节

3. 超时后窗口变化题

典型题:cwnd = 34KB 时超时,后续 4RTT 均成功,问 cwnd

结论:
16KB

关键词:
ssthresh = 17KBcwnd = 1KB,然后 1 -> 2 -> 4 -> 8 -> 16

4. 冗余 ACK 后窗口变化题

典型题:cwnd = 34KB 时收到 3 个冗余 ACK,后续 4RTT 成功,问 cwnd

结论:
按常规考研思路,取 21KB

关键词:
快重传、快恢复、Reno、不回到 1 MSS

5. 接收窗口限制发送窗口题

典型题:cwnd 算出来比 rwnd 大,问下一个 RTT 最多能发多少。

结论:
必须用 min(cwnd, rwnd)

关键词:
窗口字段、接收方缓存限制、不要只盯着 cwnd

6. 慢开始达到某窗口值题

典型题:MSS = 2KBrwnd = 24KBRTT = 10ms,无拥塞,问何时达到第一个完整窗口。

结论:
40ms

关键词:
慢开始翻倍,2 -> 4 -> 8 -> 16 -> 32,发送窗口达 24KB


十一、最后整理成一个考场速判表

这部分最适合考前过一遍。

题目问法第一反应核心公式 / 规则
求某段 seq看它前面有多少字节数据后段seq = 前段seq + 前段数据长度
求 ack看按序连续收到了哪里ack = 下一个期望字节号
中间丢失、后段先到按累计确认处理不能跨过缺口确认
问握手/挥手时间先拆 RTT/2画时间线逐段推
问超时后窗口先减半再回 1ssthresh = cwnd/2cwnd = 1 MSS
问 3 个冗余 ACK 后窗口快重传 / 快恢复不按超时处理
问下轮慢开始发多少直接翻倍k -> 2k
问发送窗口最后比一次swnd = min(cwnd, rwnd)
问何时达到某窗口值先推 cwnd,再看 rwnd先增长,再限幅

十二、这一章真正应该建立起来的感觉

TCP 这一章最关键的不是死记很多零碎定义,而是脑子里要有一条非常清楚的主线:

seq / ack 解决的是“字节流编号与确认”的问题;
RTT 解决的是“报文往返时间怎么推”的问题;
rwnd 解决的是“接收方吃不吃得下”的问题;
cwnd 解决的是“网络能不能承受”的问题;
真正发多少,最终都落到:

发送窗口 = min(cwnd, rwnd)

而一旦网络出问题,还要继续分清:

  • 超时:处理更狠
  • 3 个冗余 ACK:处理较轻

只要这一条主线真正打通,后面无论题目怎么换名字、换数字、换叙述方式,本质上都只是把这几个量重新排列组合一下而已。


十三、适合最后复习时直接记住的结论

最后可以把这一部分压缩成几句最关键的话,做题前先在脑子里过一遍:

seq 看本段第一个字节。
ack 看下一个期待字节。
TCP 默认累计确认,中间缺失不能跳确认。
SYNFIN 各消耗 1 个序号。
单程传播时延 = RTT/2
发送窗口 swnd = min(cwnd, rwnd)
慢开始按 RTT 翻倍,拥塞避免按 RTT 加 1 MSS。
超时回到 1 MSS,3 个冗余 ACK 不按超时处理。

下面把第 40~46 题逐题解析。这里这一组题几乎都在考 TCP 的几个高频核心点:seq/ack 的计算、累计确认、SYN 是否占 1 个序号、发送窗口受 min(cwnd, rwnd) 限制、超时后的拥塞窗口变化。
这类题的共同特点是:题干不长,但很容易因为“少看一个条件”或者“把几个窗口混在一起”而做错。


40. 慢开始到发送窗口达到 8KB

题目结论:B.9ms,9KB

这题考的是 TCP 建连后,发送方在慢开始阶段窗口如何增长,以及接收缓存空间如何同步减少。

题干给出:

  • MSS = 1KB
  • RTT = 3ms
  • 乙接收缓存 = 16KB
  • 乙只接收数据,不取走数据
  • 问:从连接建立成功到甲的发送窗口达到 8KB,最少经过多久?此时乙接收缓存剩余多少可用空间?

这里按考研题的默认模型,建连成功后:

  • 初始拥塞窗口 cwnd = 1 MSS = 1KB
  • 慢开始阶段每经过 1 个 RTT,cwnd 翻倍

所以窗口变化过程是:

  • 刚建连成功:cwnd = 1KB
  • 1 个 RTT 后:cwnd = 2KB
  • 2 个 RTT 后:cwnd = 4KB
  • 3 个 RTT 后:cwnd = 8KB

因此最少时间是:

3 × RTT = 3 × 3ms = 9ms

再看此时乙已经收到了多少数据。

慢开始发送的数据轮次是:

  • 第 1 轮发 1KB
  • 第 2 轮发 2KB
  • 第 3 轮发 4KB

到发送窗口第一次达到 8KB这一刻,前面总共已经成功收到的数据量是:

1 + 2 + 4 = 7KB

因为乙的接收缓存总共 16KB,而且题目说只进不出,所以可用空间还剩:

16KB - 7KB = 9KB

所以答案是 B

这题最容易错在两个地方。

第一,很多人会把“窗口达到 8KB”误看成“已经发出了 8KB”,于是把数据量算错。实际上这里是 cwnd 增长到 8KB,而不是已经额外又发了 8KB。

第二,接收缓存剩余空间算的是已经收到并留在缓存里的数据量,不是当前发送窗口大小。


41. 两个连续 TCP 段的确认号

题目结论:D.1000

这题是最标准的 seq/ack 入门题。

题干说:

  • 两个连续 TCP 段
  • 有效载荷分别为 300B、500B
  • 第一个段的序号是 200
  • 主机乙正确收到这两个数据段后,发回确认号是多少

要记住一个基本原则:

TCP 的确认号 ack = 期望收到的下一个字节序号

第一个段:

  • seq = 200
  • 长度 = 300B

所以第一个段覆盖的字节范围是:

200 ~ 499

那么第二个段的起始序号就是:

500

第二个段长度 500B,所以覆盖:

500 ~ 999

那么接收方在正确收到这两个段之后,下一字节应为:

1000

所以确认号是 1000,答案选 D

这类题一定不要把确认号理解成“已经收到了多少字节”,它不是“字节数”,而是下一个期望字节的编号


42. 超时后 4 个 RTT 的拥塞窗口

题目结论:C.9KB

这题是 TCP 拥塞控制里的经典考法,考的是:

  • 超时发生后怎么处理
  • ssthresh 怎么变
  • 接下来是慢开始还是拥塞避免

题干给出:

  • 以 1KB 为 MSS 发送
  • 当前 cwnd = 16KB 时发生超时
  • 接下来 4 个 RTT 内传输都成功
  • 问:当第 4 个 RTT 内发送的所有 TCP 段都得到确认时,拥塞窗口是多少

发生超时后,按考研标准 TCP 规则:

  • ssthresh = cwnd / 2 = 8KB
  • cwnd = 1KB

然后重新开始发送。

前 3 个 RTT:慢开始

  • 第 1 个 RTT 后:cwnd = 2KB
  • 第 2 个 RTT 后:cwnd = 4KB
  • 第 3 个 RTT 后:cwnd = 8KB

此时已经到达门限 ssthresh = 8KB

第 4 个 RTT:进入拥塞避免

进入拥塞避免后,每经过 1 个 RTT,cwnd 线性加 1 MSS,也就是加 1KB。

所以第 4 个 RTT 内的报文都确认后:

cwnd = 8KB + 1KB = 9KB

答案就是 C

这题最常见的误区有两个。

一个误区是把第 4 个 RTT 还当成慢开始,于是继续翻倍到 16KB,这就错了。因为慢开始只在 cwnd < ssthresh 时进行,到了门限后就该转入拥塞避免。

另一个误区是认为超时后 cwnd 直接减半到 8KB,这也不对。减半的是 ssthresh,不是 cwnd;超时后 cwnd 要回到 1 MSS。


43. 同时受 cwnd 和 rwnd 约束时还能发多少

题目结论:A.1000

这题专门考“发送窗口到底取谁”。

题干给出:

  • 已建 TCP 连接
  • MSS = 1000B
  • 当前 cwnd = 4000B
  • 甲连续发送了两个最大段,也就是一共发了 2000B
  • 成功收到第一个段的确认
  • 这个确认中通告的接收窗口 rwnd = 2000B
  • 问此时甲还可以发送的最大字节数是多少

TCP 发送方真正可发送的窗口大小是:

发送窗口 = min(cwnd, rwnd)

现在:

  • cwnd = 4000B
  • rwnd = 2000B

所以发送窗口上限变成:

min(4000, 2000) = 2000B

但注意,甲之前已经连续发了两个最大段,共 2000B。
现在只收到了第一个段的确认,说明还有第二个段 1000B 仍在途、未确认

因此当前还能继续发送的最大字节数为:

发送窗口 2000B - 未确认数据 1000B = 1000B

所以答案是 A

这题最容易错在把“接收窗口 2000B”直接当成“还能再发 2000B”。不对,因为其中已经有 1000B 还没被确认,占着窗口。


44. 三次握手第二次报文怎么判断

题目结论:C

题干说:

  • 甲向乙发送一个连接请求段:SYN = 1, seq = 11220
  • 若乙接受该请求
  • 问乙发回的正确 TCP 段可能是哪个

先抓住三次握手第 2 次报文的标准形式:

  • SYN = 1
  • ACK = 1
  • ack = 对方seq + 1

因为 SYN 会消耗一个序号

所以这里乙发回时,确认号必须是:

11220 + 1 = 11221

因此至少要满足:

  • SYN = 1
  • ACK = 1
  • ack = 11221

四个选项里只有 C 符合:

(SYN=1, ACK=1, seq=11221, ack=11221)

所以答案是 C

这里要顺手强调一个非常容易混的点:

seqack 没有必然相等关系

  • ack 是对对方序号的确认
  • seq自己这边当前报文段的序号

只是在这个选项题里,正好只有 C 同时满足握手格式和确认规则。
严格地说,乙的 seq 是自己的初始序号,本来可以是别的值,不需要由甲的序号推出。但在四个选项中,只有 C 是可能的。


45. 累计确认 + 中间段丢失

题目结论:B.500

题干给出:

  • 已建 TCP 连接
  • 甲发了 3 个连续 TCP 段
  • 有效载荷分别为 300B、400B、500B
  • 第 3 个段的序号为 900
  • 乙只正确收到第 1 个段和第 3 个段
  • 问乙发给甲的确认号是多少

这题先要反推 3 个段的起始序号。

第 3 段长度 500B,起始序号是 900。
第 2 段在它前面,长度 400B,所以第 2 段起始序号是:

900 - 400 = 500

第 1 段长度 300B,所以第 1 段起始序号是:

500 - 300 = 200

于是三个段分别是:

  • 第 1 段:seq = 200,长度 300B
  • 第 2 段:seq = 500,长度 400B
  • 第 3 段:seq = 900,长度 500B

现在乙收到的是第 1 段和第 3 段,但第 2 段没收到

TCP 采用的是累计确认
也就是说,确认号只能确认“按序连续收到的数据的下一个字节”。

乙已经按序收到第 1 段,所以此时下一个期待字节是:

200 + 300 = 500

虽然第 3 段也到了,但因为第 2 段缺失,中间断开,确认号不能跳过去确认到 1400。

所以乙发回的确认号仍是 500,答案选 B

这题是累计确认的标准陷阱题。
凡是中间有洞,哪怕后面的段到了,ack 也卡在缺口处不动


46. 收到一个 TCP 段后立即回段,seq/ack 怎么写

题目结论:B.2046,2013

题干说:

  • 甲乙之间已建 TCP 连接
  • 一直在双向传输,且无差错无丢失
  • 甲收到一个来自乙的 TCP 段:
    • seq = 1913
    • ack = 2046
    • 有效载荷 = 100B
  • 问甲立即发给乙的 TCP 段的序号和确认序号分别是多少

先看确认号 ack

乙发来的这个段从字节 1913 开始,长度 100B,所以包含的是:

1913 ~ 2012

那么甲收到后,下一步期望乙发送的字节序号应为:

2013

所以甲回给乙的确认号应该是:

ack = 2013

再看甲自己发送段的序号 seq

对方报文中的 ack = 2046,表示:

乙已经成功收到甲发到 2045 为止的数据,现在期待甲从 2046 开始继续发。

所以甲此时立即发出的 TCP 段,其序号应是:

seq = 2046

因此答案是:

  • seq = 2046
  • ack = 2013

也就是 B

这题最容易错的是把纯确认段也当成“会自动加 1”。
实际上:

  • SYNFIN 各占 1 个序号
  • 纯 ACK 如果不带数据,不额外消耗序号

所以这里 seq 仍应是 2046,不是 2047。


这 7 题背后其实就是 5 条规则

这几题虽然看起来分散,但真正反复考的就下面几条。

第一,确认号 ack 永远表示“期望收到的下一个字节序号”
不是“本次收到的最后一个字节”,也不是“本次数据长度”。

第二,SYN 和 FIN 各消耗 1 个序号,纯 ACK 不消耗序号
这条在握手、挥手题里极其高频。

第三,TCP 默认是累计确认
中间有一个段没到,后面即便到了,确认号也不能跳过去。

第四,发送方真正能发多少,取决于:

发送窗口 = min(cwnd, rwnd)

如果还有未确认数据在路上,还要再减掉这部分。

第五,超时后:

  • ssthresh = 当前cwnd / 2
  • cwnd = 1 MSS
  • 然后重新慢开始,到门限后转拥塞避免

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇