Appearance
TCP 拥塞控制典型计算题
考情分析
TCP 拥塞控制的计算题是 408 大题的常见题型。典型的出题模式:给定初始 cwnd、ssthresh,以及在某些轮次发生的事件(超时或 3 个冗余 ACK),要求写出每一轮的 cwnd 值或画出 cwnd 变化曲线。这类题目只要掌握规则,做题流程是固定的。
考频:★★★★★
拥塞控制规则速查
在做题之前,先把 TCP Reno 的规则整理清楚。408 默认考 Reno。
正常传输时
| 当前阶段 | 条件 | cwnd 变化 |
|---|---|---|
| 慢开始 | cwnd < ssthresh | 每经过一个 RTT,cwnd 翻倍 |
| 拥塞避免 | cwnd >= ssthresh | 每经过一个 RTT,cwnd + 1 |
发生事件时
| 事件 | ssthresh 更新 | cwnd 更新 | 进入阶段 |
|---|---|---|---|
| 超时 | cwnd / 2 | 1 | 慢开始 |
| 3 个冗余 ACK | cwnd / 2 | ssthresh(即 cwnd/2) | 拥塞避免 |
注意执行顺序:先更新 ssthresh,再更新 cwnd。这个顺序很重要,搞反就全错了。
关于 cwnd = ssthresh
当 cwnd 恰好等于 ssthresh 时,按哪个阶段执行?不同教材说法不一,但 408 默认:cwnd = ssthresh 时执行拥塞避免(即开始 +1)。做题时注意审题是否有特殊说明。
做题步骤
遇到拥塞控制计算题,按以下步骤操作:
第一步:列出初始参数(cwnd 初始值、ssthresh 初始值)
第二步:从第 0 轮开始,逐轮计算 cwnd
- 判断当前阶段(慢开始 or 拥塞避免)
- 应用对应规则计算下一轮的 cwnd
- 如果本轮发生了事件,先处理事件再计算
第三步:画表格或曲线图
建议画表格,每一行记录:轮次、cwnd、ssthresh、阶段、说明。这样不容易出错。
例题一:TCP Reno 完整计算
题目: TCP 连接使用 Reno 算法,初始 cwnd=1 MSS,ssthresh=16 MSS。在第 14 轮传输结束时收到 3 个冗余 ACK,在第 22 轮传输结束时发生超时。求每一轮的 cwnd 值。
解题过程
阶段一:慢开始(第 0~4 轮)
初始 ssthresh=16,cwnd 从 1 开始指数增长。
| 轮次 | cwnd | ssthresh | 阶段 |
|---|---|---|---|
| 0 | 1 | 16 | 慢开始 |
| 1 | 2 | 16 | 慢开始 |
| 2 | 4 | 16 | 慢开始 |
| 3 | 8 | 16 | 慢开始 |
| 4 | 16 | 16 | cwnd = ssthresh |
阶段二:拥塞避免(第 4~14 轮)
cwnd = ssthresh = 16,进入拥塞避免,每轮 +1。
| 轮次 | cwnd | ssthresh | 阶段 |
|---|---|---|---|
| 4 | 16 | 16 | 拥塞避免 |
| 5 | 17 | 16 | 拥塞避免 |
| 6 | 18 | 16 | 拥塞避免 |
| 7 | 19 | 16 | 拥塞避免 |
| 8 | 20 | 16 | 拥塞避免 |
| 9 | 21 | 16 | 拥塞避免 |
| 10 | 22 | 16 | 拥塞避免 |
| 11 | 23 | 16 | 拥塞避免 |
| 12 | 24 | 16 | 拥塞避免 |
| 13 | 25 | 16 | 拥塞避免 |
| 14 | 26 | 16 | 3 个冗余 ACK |
阶段三:快恢复 + 拥塞避免(第 14 轮事件处理后~第 22 轮)
第 14 轮结束时收到 3 个冗余 ACK:
(= ssthresh) - 进入拥塞避免
| 轮次 | cwnd | ssthresh | 阶段 |
|---|---|---|---|
| 15 | 13 | 13 | 拥塞避免 |
| 16 | 14 | 13 | 拥塞避免 |
| 17 | 15 | 13 | 拥塞避免 |
| 18 | 16 | 13 | 拥塞避免 |
| 19 | 17 | 13 | 拥塞避免 |
| 20 | 18 | 13 | 拥塞避免 |
| 21 | 19 | 13 | 拥塞避免 |
| 22 | 20 | 13 | 超时 |
阶段四:超时后重新慢开始(第 22 轮事件处理后)
第 22 轮结束时超时:
- 回到慢开始
| 轮次 | cwnd | ssthresh | 阶段 |
|---|---|---|---|
| 23 | 1 | 10 | 慢开始 |
| 24 | 2 | 10 | 慢开始 |
| 25 | 4 | 10 | 慢开始 |
| 26 | 8 | 10 | 慢开始 |
| 27 | 10 | 10 | cwnd = ssthresh,转拥塞避免 |
| 28 | 11 | 10 | 拥塞避免 |
完整 cwnd 变化汇总
轮次: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 15 16 17 18 19 20 21 22 | 23 24 25 26 27 28
cwnd: 1 2 4 8 16 17 18 19 20 21 22 23 24 25 26 | 13 14 15 16 17 18 19 20 | 1 2 4 8 10 11
3冗余ACK↑ 超时↑例题二:TCP Tahoe 对比
如果把例题一改成 TCP Tahoe,区别在于对 3 个冗余 ACK 的处理方式。
Tahoe 把 3 个冗余 ACK 当作超时处理:
- 回到慢开始
所以第 14 轮收到 3 个冗余 ACK 后:
(不是 13!) - 回到慢开始
| 轮次 | cwnd (Reno) | cwnd (Tahoe) | 区别 |
|---|---|---|---|
| 14 | 26 (事件) | 26 (事件) | 相同 |
| 15 | 13 | 1 | Reno 快恢复,Tahoe 慢开始 |
| 16 | 14 | 2 | — |
| 17 | 15 | 4 | — |
| 18 | 16 | 8 | — |
| 19 | 17 | 13 | Tahoe 此时才到 ssthresh |
Tahoe 的恢复明显更慢——需要经历完整的慢开始阶段才能回到正常水平。这就是 Reno 引入快恢复的意义。
例题三:含 rwnd 限制的综合题
题目: TCP Reno,cwnd=1,ssthresh=8,rwnd=20。第 10 轮超时。求第 0~15 轮的发送窗口大小。
这道题的关键:发送窗口 = min(cwnd, rwnd)。
| 轮次 | cwnd | ssthresh | min(cwnd,rwnd) | 阶段 |
|---|---|---|---|---|
| 0 | 1 | 8 | 1 | 慢开始 |
| 1 | 2 | 8 | 2 | 慢开始 |
| 2 | 4 | 8 | 4 | 慢开始 |
| 3 | 8 | 8 | 8 | 拥塞避免 |
| 4 | 9 | 8 | 9 | 拥塞避免 |
| 5 | 10 | 8 | 10 | 拥塞避免 |
| 6 | 11 | 8 | 11 | 拥塞避免 |
| 7 | 12 | 8 | 12 | 拥塞避免 |
| 8 | 13 | 8 | 13 | 拥塞避免 |
| 9 | 14 | 8 | 14 | 拥塞避免 |
| 10 | 15 | 8 | 15 | 超时 |
| — | — | 7 | — | ssthresh=15/2=7(取整),cwnd=1 |
| 11 | 1 | 7 | 1 | 慢开始 |
| 12 | 2 | 7 | 2 | 慢开始 |
| 13 | 4 | 7 | 4 | 慢开始 |
| 14 | 7 | 7 | 7 | 拥塞避免 |
| 15 | 8 | 7 | 8 | 拥塞避免 |
这道题中 rwnd=20 始终大于 cwnd,所以发送窗口 = cwnd。但如果 rwnd 很小(比如 rwnd=10),那从第 5 轮开始发送窗口就会被 rwnd 限制在 10。
注意:ssthresh 除以 2 如果不是整数,取整方式要看题目说明。常见做法是向下取整,但有些题目会特别说明。
例题四:吞吐量计算
题目: TCP Reno,cwnd=1,ssthresh=32。假设不发生任何拥塞事件,在前 10 个 RTT 内,发送方总共能发送多少个 MSS 的数据?
这类题目考的不是 cwnd 的最终值,而是所有轮次 cwnd 的累加和。
| 轮次 | cwnd | 累计发送量 |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 3 | 4 | 7 |
| 4 | 8 | 15 |
| 5 | 16 | 31 |
| 6 | 32 | 63 |
| 7 | 33 | 96 |
| 8 | 34 | 130 |
| 9 | 35 | 165 |
| 10 | 36 | 201 |
前 5 轮是慢开始(cwnd < 32),第 6 轮 cwnd=32=ssthresh 转拥塞避免,之后每轮 +1。
总发送量 = 1+2+4+8+16+32+33+34+35+36 = 201 MSS。
这种题要注意:每一轮发送的数据量等于该轮的 cwnd 值(假设每轮都能把窗口用满)。
常见变体题型
除了标准的逐轮 cwnd 计算,还有几种变体需要注意:
变体一:求某一轮的 ssthresh 值
有些题目不直接问 cwnd,而是问"第 X 轮的 ssthresh 是多少"。ssthresh 只在发生事件时才改变,平时保持不变。所以关键是找到最近一次事件时 ssthresh 被设置成了多少。
变体二:给出 cwnd 变化曲线,反推事件
题目给出一段 cwnd 变化曲线(比如先指数增长到 32,然后突然降到 1),要求判断在哪些轮次发生了什么事件。
- cwnd 突然降到 1:超时
- cwnd 突然降到某个大于 1 的值:3 个冗余 ACK(快恢复)
- 指数增长 → 线性增长的转折点:cwnd 到达 ssthresh
变体三:结合传输效率
如果题目给了 RTT 和报文段传输时延,需要计算有效吞吐量。这种题不常见,但偶尔出现。
做题模板
遇到拥塞控制计算题,直接画这个表格:
| 轮次 | cwnd | ssthresh | 阶段 | 事件 | 发送窗口 |
|---|---|---|---|---|---|
| 0 | (初始值) | (初始值) | 慢开始 | — | min(cwnd,rwnd) |
| 1 | ... | ... | ... | ... | ... |
然后逐行填写,遇到事件就先处理事件再继续。
易错点
1. 事件发生在"第 X 轮"还是"第 X 轮结束时"
这个措辞很关键。"第 14 轮发生超时"一般理解为第 14 轮传输的数据触发了超时,所以第 14 轮的 cwnd 还是按之前的规则算出来的,事件的影响从第 15 轮开始体现。但有些题目会说"在 cwnd=X 时超时",这种情况直接从该点开始处理。一定要仔细审题。
2. ssthresh 的计算用的是事件发生时的 cwnd
先算 ssthresh = cwnd/2,再设置新的 cwnd。不是用新的 cwnd 来算 ssthresh。
3. 慢开始阶段 cwnd 到达 ssthresh 后的处理
如果慢开始阶段 cwnd 翻倍后恰好等于 ssthresh,那么该轮 cwnd 就是 ssthresh 的值,下一轮开始拥塞避免(+1)。如果 cwnd 翻倍后超过了 ssthresh(比如 cwnd=6,ssthresh=10,翻倍后 cwnd=12>10),通常认为 cwnd 直接取 ssthresh 的值(cwnd=10),然后转拥塞避免。但这个细节在不同教材中有争议,做题时看上下文。
4. Tahoe 和 Reno 的默认选择
408 默认是 Reno,除非题目明确说用 Tahoe。如果题目只说"TCP 拥塞控制"而没指定版本,按 Reno 做。
5. cwnd 的单位
题目中 cwnd 的单位可能是 MSS,也可能是字节。注意审题。大多数 408 题目用 MSS 作为单位。
快速检验方法
做完题后,可以用以下方法检验答案:
检验一:慢开始阶段 cwnd 是否翻倍
慢开始阶段每轮 cwnd 应该是 1→2→4→8→16→...,如果中间出现了不是 2 的幂次方的值(或者不是连续翻倍的),说明某一步算错了。
检验二:事件处理后 ssthresh 是否合理
ssthresh = cwnd/2,所以 ssthresh 一定不超过事件发生时的 cwnd 值的一半。如果算出来 ssthresh 比事件前的 cwnd 还大,肯定错了。
检验三:拥塞避免阶段是否每轮 +1
拥塞避免阶段 cwnd 应该是 ssthresh→ssthresh+1→ssthresh+2→...,如果出现跳跃或翻倍,说明阶段判断错了。
检验四:快恢复后 cwnd 不应该是 1
Reno 算法中,3 个冗余 ACK 后 cwnd = ssthresh(不是 1)。如果 cwnd 降到了 1,只有两种可能:要么是超时事件,要么是 Tahoe 算法。
高频考点清单
- 慢开始:cwnd 指数增长(每 RTT 翻倍),直到 cwnd = ssthresh
- 拥塞避免:cwnd 线性增长(每 RTT +1)
- 超时处理:ssthresh = cwnd/2,cwnd = 1,慢开始
- 3 个冗余 ACK 处理(Reno):ssthresh = cwnd/2,cwnd = ssthresh,拥塞避免
- 发送窗口 = min(cwnd, rwnd)
- Tahoe vs Reno 对 3 个冗余 ACK 的不同响应
- 逐轮 cwnd 计算的做题流程
- ssthresh 的更新顺序:先算 ssthresh,再设 cwnd