16天:TCP可靠传输机制

第16天:TCP可靠传输机制

今日目标

  • 深入理解TCP序列号和确认号机制
  • 掌握TCP滑动窗口原理
  • 理解超时重传机制
  • 掌握快速重传和快速恢复算法
  • 理解TCP流量控制
  • 理解TCP拥塞控制算法
  • 实现TCP可靠性分析工具

1. TCP可靠传输概述

1.1 什么是可靠传输?

可靠传输的保证

1. 数据无差错
   └─ 通过校验和检测

2. 数据不丢失
   └─ 通过确认和重传

3. 数据不重复
   └─ 通过序列号去重

4. 数据按序到达
   └─ 通过序列号排序

5. 流量控制
   └─ 防止发送方发送过快

6. 拥塞控制
   └─ 防止网络过载

1.2 可靠传输的核心机制

┌─────────────────────────────────────────┐
│         TCP可靠传输机制                   │
├─────────────────────────────────────────┤
│ 1. 序列号 (Sequence Number)             │
│    └─ 标识每个字节                       │
│                                          │
│ 2. 确认应答 (ACK)                       │
│    └─ 确认收到的数据                     │
│                                          │
│ 3. 超时重传 (Retransmission)            │
│    └─ 超时未收到ACK则重传                │
│                                          │
│ 4. 滑动窗口 (Sliding Window)            │
│    └─ 流量控制和效率提升                 │
│                                          │
│ 5. 快速重传 (Fast Retransmit)           │
│    └─ 收到3个重复ACK立即重传             │
│                                          │
│ 6. 拥塞控制 (Congestion Control)        │
│    └─ 慢启动、拥塞避免、快速恢复         │
└─────────────────────────────────────────┘

2. 序列号和确认号

2.1 序列号机制

序列号(Sequence Number)

作用:标识发送的每个字节在字节流中的位置

特点:
- 32位,范围:0 ~ 4,294,967,295 (约4GB)
- 超过最大值会回绕(wraparound)
- 初始序列号(ISN)在连接时随机选择

示例:
┌─────────────────────────────────────────┐
│   字节流:HELLO WORLD                    │
├─────────────────────────────────────────┤
│   位置:  0 1 2 3 4 5 6 7 8 9 10        │
│   字符:  H E L L O   W O R L D         │
└─────────────────────────────────────────┘

如果ISN = 1000:
- 'H' 的序列号:1000
- 'E' 的序列号:1001
- 'L' 的序列号:1002
- ...
- 'D' 的序列号:1010

TCP段的序列号

TCP段的序列号 = 该段第一个字节的序列号

示例:
发送 "HELLO WORLD" (11字节)

方案1:一次发送
┌──────────────────────────────┐
│ SEQ=1000, Data="HELLO WORLD" │
│ 长度:11字节                  │
└──────────────────────────────┘

方案2:分两次发送
┌──────────────────────────────┐
│ SEQ=1000, Data="HELLO "      │  (6字节)
│ SEQ=1006, Data="WORLD"       │  (5字节)
└──────────────────────────────┘

下一个段的SEQ:
= 当前SEQ + 当前段数据长度
= 1000 + 11 = 1011

2.2 确认号机制

确认号(Acknowledgment Number)

作用:告诉对方期望接收的下一个字节的序列号

含义:
ACK = n 表示 "我已经收到了序列号 < n 的所有数据"

特点:
- 累积确认(Cumulative ACK)
- 确认号之前的所有数据都已收到

确认示例

发送方                                     接收方
  |                                          |
  | SEQ=1000, Len=100 ("数据1")             |
  |─────────────────────────────────────────>|
  |                                          |
  |                  ACK=1100                |
  |<─────────────────────────────────────────|
  |    (已收到1000-1099,期望1100)           |
  |                                          |
  | SEQ=1100, Len=50 ("数据2")              |
  |─────────────────────────────────────────>|
  |                                          |
  |                  ACK=1150                |
  |<─────────────────────────────────────────|
  |    (已收到1100-1149,期望1150)           |

累积确认的问题

发送方发送了3个段:
  段1: SEQ=1000, Len=100
  段2: SEQ=1100, Len=100
  段3: SEQ=1200, Len=100

情况1:全部收到
  接收方回复:ACK=1300 ✅

情况2:段2丢失
  段1到达 → 回复 ACK=1100
  段3到达 → 还是回复 ACK=1100(期望1100)

  问题:发送方不知道段3是否收到
  解决:SACK(选择性确认)扩展

2.3 序列号回绕问题

序列号是32位:0 ~ 4,294,967,295 (约4GB)

高速网络问题:
- 10 Gbps 网络
- 发送速度:1.25 GB/s
- 序列号耗尽时间:4GB ÷ 1.25GB/s ≈ 3.2秒

解决方案:
1. PAWS (Protection Against Wrapped Sequence numbers)
   └─ 使用时间戳选项
2. TCP窗口扩大选项
   └─ 减少数据段数量

3. 滑动窗口机制

3.1 为什么需要滑动窗口?

停止等待协议的问题

停止等待 (Stop-and-Wait):
1. 发送一个段
2. 等待ACK
3. 收到ACK后发送下一个段

效率:非常低

示例:
RTT = 100ms
数据段大小 = 1KB

时间线:
t=0ms:    发送段1
t=100ms:  收到ACK1
t=100ms:  发送段2
t=200ms:  收到ACK2
...

吞吐量 = 1KB / 100ms = 10KB/s = 80Kbps

即使带宽是1Gbps,也只能用到80Kbps!❌

滑动窗口解决方案

连续发送多个段,不用等待ACK

示例(窗口大小=4):
t=0ms:    发送段1、段2、段3、段4
t=100ms:  收到ACK1,窗口滑动,发送段5
t=105ms:  收到ACK2,窗口滑动,发送段6
...

吞吐量大幅提升!✅

3.2 发送窗口

发送窗口结构

字节流:
┌────────────────────────────────────────────────────┐
│ 已发送  │  已发送   │   可以发送    │    不能发送   │
│ 已确认  │  未确认   │   (窗口内)    │   (窗口外)    │
└────────────────────────────────────────────────────┘
    ↑          ↑             ↑              ↑
   P1         P2            P3             P4

P1: 已发送并已确认的最后一个字节
P2: 已发送但未确认的最后一个字节
P3: 允许发送的最后一个字节
P4: 未来的数据

发送窗口 = P3 - P1
可用窗口 = P3 - P2
已发送未确认 = P2 - P1

窗口滑动过程

初始状态(窗口大小=6):
┌────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 1  │ 2  │ 3  │ 4  │ 5  │ 6  │ 7  │ 8  │ 9  │
└────┴────┴────┴────┴────┴────┴────┴────┴────┘
       └────────窗口────────┘
       可发送:1,2,3,4,5,6

步骤1:发送1,2,3
┌────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 1* │ 2* │ 3* │ 4  │ 5  │ 6  │ 7  │ 8  │ 9  │
└────┴────┴────┴────┴────┴────┴────┴────┴────┘
       └────────窗口────────┘
       *=已发送

步骤2:收到ACK for 1,2
┌────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 1✓ │ 2✓ │ 3* │ 4  │ 5  │ 6  │ 7  │ 8  │ 9  │
└────┴────┴────┴────┴────┴────┴────┴────┴────┘
             └────────窗口────────┘
             窗口向右滑动2格

步骤3:可以发送7,8
┌────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 1✓ │ 2✓ │ 3* │ 4  │ 5  │ 6  │ 7  │ 8  │ 9  │
└────┴────┴────┴────┴────┴────┴────┴────┴────┘
             └────────窗口────────┘
             发送7,8

3.3 接收窗口

接收窗口结构

字节流:
┌────────────────────────────────────────────────────┐
│   已接收    │    可以接收      │      不能接收      │
│   已确认    │   (窗口内)       │     (窗口外)       │
└────────────────────────────────────────────────────┘
       ↑             ↑                  ↑
      Q1            Q2                 Q3

Q1: 已接收并已确认的最后一个字节
Q2: 期望接收的最后一个字节
Q3: 不能接收的第一个字节

接收窗口 = Q3 - Q1

乱序到达的处理

期望接收顺序:1, 2, 3, 4, 5

实际到达顺序:1, 3, 2, 5, 4

处理:
1. 收到1 → 交付应用层,ACK=2
2. 收到3 → 缓存(等待2),ACK=2
3. 收到2 → 交付1,2,3,ACK=4
4. 收到5 → 缓存(等待4),ACK=4
5. 收到4 → 交付4,5,ACK=6

策略:
- 按序交付给应用层
- 乱序数据暂存在缓冲区
- 累积确认

3.4 窗口大小的影响

带宽延迟积(BDP)

BDP = 带宽 × RTT

示例:
带宽 = 100 Mbps = 12.5 MB/s
RTT = 100 ms = 0.1 s

BDP = 12.5 MB/s × 0.1s = 1.25 MB

含义:
- 在收到ACK前,可以发送1.25MB数据
- 窗口大小应该 ≥ BDP
- 否则无法充分利用带宽

窗口大小限制

TCP头部窗口字段:16位
最大窗口大小:2^16 = 65536 字节 = 64 KB

问题:
高速长延迟网络(如卫星链路)需要更大窗口

解决:
窗口扩大选项 (Window Scale Option)
实际窗口 = 窗口字段值 × 2^Scale
最大Scale = 14
最大窗口 = 65536 × 2^14 = 1 GB

4. 超时重传机制

4.1 超时重传原理

发送方行为:
1. 发送数据段
2. 启动重传计时器
3. 如果超时仍未收到ACK
   └─ 重传该数据段
4. 收到ACK
   └─ 取消计时器

超时重传示例

发送方                                     接收方
  |                                          |
  | SEQ=1000, Len=100                       |
  |─────────────────────────────────────────>|
  | [启动计时器]                              |
  |                                          |
  |                                       ❌ 数据丢失
  |                                          |
  | [超时!]                                 |
  | SEQ=1000, Len=100 (重传)                |
  |─────────────────────────────────────────>|
  |                                          |
  |                  ACK=1100                |
  |<─────────────────────────────────────────|
  | ✅ 收到ACK,取消计时器                    |

4.2 重传超时时间(RTO)的计算

问题:RTO设置多少合适?

RTO太小:
- 不必要的重传
- 浪费带宽
- 加重网络负担

RTO太大:
- 重传延迟大
- 影响性能
- 用户体验差

理想:RTO 略大于 RTT

RTO计算算法(Jacobson算法)

1. 测量RTT样本(每次收到ACK时)
   RTT_sample = ACK到达时间 - 发送时间

2. 计算平滑RTT(SRTT)
   SRTT = (1 - α) × SRTT + α × RTT_sample
   α = 0.125 (1/8)

3. 计算RTT变化(RTTVAR)
   RTTVAR = (1 - β) × RTTVAR + β × |SRTT - RTT_sample|
   β = 0.25 (1/4)

4. 计算RTO
   RTO = SRTT + 4 × RTTVAR
   最小值:200ms(Linux默认)
   最大值:120秒

示例:
假设:
RTT样本序列:100ms, 110ms, 90ms, 105ms

初始:SRTT=100ms, RTTVAR=0

第1次:RTT=110ms
SRTT = 0.875×100 + 0.125×110 = 101.25ms
RTTVAR = 0.75×0 + 0.25×|100-110| = 2.5ms
RTO = 101.25 + 4×2.5 = 111.25ms

第2次:RTT=90ms
SRTT = 0.875×101.25 + 0.125×90 = 99.84ms
RTTVAR = 0.75×2.5 + 0.25×|101.25-90| = 4.69ms
RTO = 99.84 + 4×4.69 = 118.6ms

4.3 重传歧义问题

问题:重传后收到ACK,这个ACK是对原始段还是重传段的确认?

场景1:ACK是对原始段的确认
发送方                                     接收方
  | SEQ=1000                                |
  |─────────────────────────────────────────>|
  | [启动计时器]                              |
  |                                          |
  |                         ACK=1100 (延迟)  |
  | [超时!重传]                 ↓            |
  | SEQ=1000 (重传)           ↓              |
  |──────────────>            ↓              |
  |                           ↓              |
  |<──────────────────────────┘              |
  | 收到ACK                                  |

  RTT计算:如果用重传时间,会高估RTT ❌

场景2:ACK是对重传段的确认
发送方                                     接收方
  | SEQ=1000                                |
  |─────────────> ❌ 丢失                    |
  | [启动计时器]                              |
  | [超时!重传]                              |
  | SEQ=1000 (重传)                         |
  |─────────────────────────────────────────>|
  |                                          |
  |                  ACK=1100                |
  |<─────────────────────────────────────────|

  RTT计算:如果用原始发送时间,会高估RTT ❌

Karn算法解决方案

规则:
1. 重传的段不用于RTT计算
2. 只用成功传输(未重传)的段计算RTT

缺点:
如果连续丢包,无法更新RTO

解决:
结合指数退避(Exponential Backoff)
每次重传,RTO翻倍
RTO_new = RTO_old × 2

5. 快速重传与快速恢复

5.1 快速重传(Fast Retransmit)

问题:超时重传太慢

传统超时重传:
- 等待RTO超时(可能几百毫秒)
- 影响传输效率

快速重传原理

规则:
收到3个重复ACK,立即重传,不等超时

为什么是3个?
- 1个重复ACK:可能是乱序到达
- 2个重复ACK:可能还是乱序
- 3个重复ACK:很可能是丢包

快速重传示例

发送方                                     接收方
  |                                          |
  | SEQ=1000, Len=100                       |
  |─────────────────────────────────────────>|
  |                  ACK=1100                |
  |<─────────────────────────────────────────|
  |                                          |
  | SEQ=1100, Len=100                       |
  |─────────>  ❌ 丢失                       |
  |                                          |
  | SEQ=1200, Len=100                       |
  |─────────────────────────────────────────>|
  |                  ACK=1100 (重复1)        |
  |<─────────────────────────────────────────|
  |                                          |
  | SEQ=1300, Len=100                       |
  |─────────────────────────────────────────>|
  |                  ACK=1100 (重复2)        |
  |<─────────────────────────────────────────|
  |                                          |
  | SEQ=1400, Len=100                       |
  |─────────────────────────────────────────>|
  |                  ACK=1100 (重复3)        |
  |<─────────────────────────────────────────|
  |                                          |
  | 🚀 收到3个重复ACK,立即重传!             |
  | SEQ=1100, Len=100 (快速重传)            |
  |─────────────────────────────────────────>|
  |                  ACK=1500                |
  |<─────────────────────────────────────────|
  | ✅ 成功恢复                               |

5.2 SACK(选择性确认)

累积ACK的局限

发送:段1(1000), 段2(1100), 段3(1200), 段4(1300)
接收:段1✓, 段2✗, 段3✓, 段4✓

累积ACK只能发送:ACK=1100
发送方不知道段3和段4是否收到

问题:
- 发送方可能重传段2、3、4(浪费)
- 只需要重传段2即可

SACK解决方案

SACK选项格式:
┌─────────────────────────────────────────┐
│ Kind=5 │ Length │ Left Edge │Right Edge │
└─────────────────────────────────────────┘

示例:
接收到:1000-1099, 1200-1299, 1300-1399

SACK选项:
ACK=1100
SACK: 1200-1300, 1300-1400

含义:
- 期望收到1100
- 但已经收到1200-1399的数据

发送方行为:
- 只重传1100-1199
- 不重传1200-1399 ✅

5.3 快速恢复(Fast Recovery)

快速恢复算法

触发:收到3个重复ACK时

步骤:
1. 拥塞窗口减半
   cwnd = cwnd / 2
   ssthresh = cwnd

2. 快速重传丢失的段

3. 每收到一个重复ACK
   cwnd = cwnd + 1 (临时膨胀)

4. 收到新的ACK
   cwnd = ssthresh (恢复正常)
   进入拥塞避免阶段

目的:
- 快速恢复,不回到慢启动
- 保持较高的发送速率

6. 流量控制

6.1 流量控制的目的

问题:
发送方发送速度 > 接收方处理速度
接收方缓冲区溢出,数据丢失

解决:
接收方通过窗口大小告诉发送方还能接收多少数据

6.2 流量控制机制

接收窗口通告

接收方在每个ACK中通告窗口大小

示例:
接收缓冲区大小:8KB
已接收未读:2KB
可用空间:6KB

发送ACK:
ACK=1000, Window=6144 (6KB)

发送方:
- 最多再发送6KB数据
- 发送后等待ACK和新的窗口通告

零窗口问题

场景:
1. 接收方缓冲区满,发送Window=0
2. 发送方停止发送
3. 接收方处理数据,缓冲区有空间
4. 但如果ACK丢失,发送方不知道可以继续发送

解决:零窗口探测
发送方定期发送零窗口探测段(1字节数据)
询问接收方是否有可用窗口

糊涂窗口综合症(Silly Window Syndrome)

问题:
接收方每次只读取很少数据
导致频繁发送小窗口通告
发送方发送大量小数据段
效率低下

示例:
缓冲区8KB,应用每次读1字节
Window序列:0, 1, 0, 1, 0, 1...
效率:极低 ❌

解决方案:
1. 接收方(Clark算法)
   - 缓冲区空间 < MSS时,通告Window=0
   - 直到有足够空间(MSS或缓冲区一半)

2. 发送方(Nagle算法)
   - 等待数据累积到MSS大小再发送
   - 或收到之前数据的ACK再发送

7. 拥塞控制

7.1 拥塞控制 vs 流量控制

流量控制(Flow Control):
- 目标:防止接收方过载
- 机制:接收窗口(rwnd)
- 控制:接收方控制发送方

拥塞控制(Congestion Control):
- 目标:防止网络过载
- 机制:拥塞窗口(cwnd)
- 控制:发送方自己判断

发送窗口 = min(rwnd, cwnd)

7.2 拥塞控制算法

1. 慢启动(Slow Start)

目的:
连接初期探测网络容量

算法:
1. 初始cwnd = 1 MSS (或更大,如10 MSS)
2. 每收到一个ACK,cwnd += 1
3. 效果:cwnd指数增长(每个RTT翻倍)

示例:
RTT 0: cwnd=1,  发送1个段
RTT 1: cwnd=2,  发送2个段
RTT 2: cwnd=4,  发送4个段
RTT 3: cwnd=8,  发送8个段
...

终止条件:
- cwnd >= ssthresh(慢启动阈值)
  → 进入拥塞避免
- 发生丢包
  → 进入拥塞避免或快速恢复

2. 拥塞避免(Congestion Avoidance)

目的:
小心翼翼地增加窗口,避免拥塞

算法:
每收到一个ACK:
cwnd = cwnd + 1/cwnd

效果:每个RTT,cwnd增加1

示例:
RTT 0: cwnd=16
RTT 1: cwnd=17
RTT 2: cwnd=18
RTT 3: cwnd=19
...

特点:线性增长(比慢启动慢得多)

3. 拥塞发生

情况1:超时(丢包严重)
行为:
- ssthresh = cwnd / 2
- cwnd = 1 MSS
- 重新慢启动

情况2:3个重复ACK(丢包较轻)
行为:
- ssthresh = cwnd / 2
- cwnd = ssthresh + 3
- 快速重传 + 快速恢复

4. 快速恢复(Fast Recovery)

算法:
1. ssthresh = cwnd / 2
2. cwnd = ssthresh + 3
3. 重传丢失的段
4. 每收到重复ACK,cwnd += 1(临时膨胀)
5. 收到新ACK时,cwnd = ssthresh
6. 进入拥塞避免

目的:
- 快速恢复,不回到慢启动
- 维持较高吞吐量

7.3 拥塞控制状态图

                 [连接建立]
                      ↓
                ┌──────────┐
                │ 慢启动    │ cwnd指数增长
                │          │ 每ACK: cwnd += 1
                └──────────┘
                      ↓
              cwnd >= ssthresh
                      ↓
                ┌──────────┐
                │拥塞避免   │ cwnd线性增长
                │          │ 每RTT: cwnd += 1
                └──────────┘
                      ↓
                  发生丢包
                   ↙    ↘
            超时         3个重复ACK
              ↓               ↓
        ┌──────────┐    ┌──────────┐
        │ 慢启动    │    │快速恢复   │
        │cwnd=1    │    │cwnd=ssthresh/2+3│
        └──────────┘    └──────────┘
              ↓               ↓
              └───────┬───────┘
                      ↓
                ┌──────────┐
                │拥塞避免   │
                └──────────┘

7.4 拥塞控制变体

TCP Reno(经典算法)

特点:
- 慢启动 + 拥塞避免 + 快速重传 + 快速恢复
- 最经典的TCP实现

问题:
- 对多个丢包处理不好
- 每个RTT只能恢复一个丢包

TCP NewReno

改进:
- 改进的快速恢复
- 可以在一个RTT内恢复多个丢包

特点:
- 部分ACK触发重传
- 直到所有丢失数据恢复才退出快速恢复

TCP CUBIC(Linux默认)

特点:
- 窗口增长函数:cwnd = C(t - K)^3 + W_max
- 更适合高带宽长延迟网络

优点:
- 快速探测可用带宽
- 公平性更好
- 高速网络性能更好

TCP BBR(Google)

理念:
- 不基于丢包,基于RTT和带宽
- 主动探测瓶颈带宽和RTT

特点:
- 4个状态:Startup, Drain, ProbeBW, ProbeRTT
- 更高吞吐量
- 更低延迟

8. 实战项目:TCP可靠性分析工具

8.1 项目功能

实现工具分析:

  1. TCP连接的重传统计
  2. RTT和RTO监控
  3. 窗口大小变化
  4. 拥塞控制状态

8.2 工具演示

# 监控TCP重传
python day16_tcp_reliability.py --monitor-retrans

# 分析RTT
python day16_tcp_reliability.py --analyze-rtt

# 模拟拥塞控制
python day16_tcp_reliability.py --simulate-congestion

# 窗口大小分析
python day16_tcp_reliability.py --window-analysis

9. 今日练习

练习1:观察重传

使用Wireshark:

  1. 访问一个网站
  2. 筛选:tcp.analysis.retransmission
  3. 观察重传的段
  4. 分析重传原因(超时/快速重传)

练习2:计算RTO

给定RTT样本:100ms, 120ms, 90ms, 110ms

计算:
1. SRTT (Smoothed RTT)
2. RTTVAR (RTT Variation)
3. RTO (Retransmission Timeout)

使用公式:
SRTT = (1-α) × SRTT + α × RTT_sample
RTTVAR = (1-β) × RTTVAR + β × |SRTT - RTT_sample|
RTO = SRTT + 4 × RTTVAR

练习3:模拟拥塞控制

场景:
- 初始cwnd = 1 MSS
- ssthresh = 16 MSS
- MSS = 1460 字节

问题:
1. 经过多少个RTT,cwnd达到16?
2. 如果在cwnd=20时发生超时,新的cwnd和ssthresh是多少?
3. 如果在cwnd=20时收到3个重复ACK,cwnd和ssthresh是多少?

练习4:查看TCP统计

# Linux查看TCP统计
netstat -s | grep -i tcp
ss -ti  # 查看TCP详细信息

# 查看重传统计
netstat -s | grep retrans

# 查看拥塞控制算法
sysctl net.ipv4.tcp_congestion_control

10. 常见问题

Q1:为什么是3个重复ACK触发快速重传,而不是2个或4个?

A:这是经验值的平衡:

  • 2个:可能误判(乱序到达)
  • 3个:较可靠地判断丢包
  • 4个:太保守,影响效率

Q2:TCP如何区分网络拥塞和接收方慢?

A:

  • 网络拥塞:超时或3个重复ACK
  • 接收方慢:Window字段变小
  • TCP会相应调整发送速度

Q3:为什么慢启动要指数增长?

A:

  • 快速探测可用带宽
  • 避免初期过于保守
  • 遇到拥塞时能快速反应

Q4:选择性确认(SACK)是必须的吗?

A:

  • 不是必须,但强烈推荐
  • 没有SACK时效率较低
  • 现代TCP实现基本都支持SACK

11. 总结

今天我们深入学习了:

核心知识点

  1. 序列号和确认号

    • 序列号标识字节位置
    • 确认号表示期望接收的下一个字节
    • 累积确认机制
  2. 滑动窗口

    • 提高传输效率
    • 发送窗口和接收窗口
    • 窗口大小 = min(rwnd, cwnd)
  3. 超时重传

    • RTO动态计算(Jacobson算法)
    • Karn算法解决重传歧义
    • 指数退避
  4. 快速重传和快速恢复

    • 3个重复ACK触发
    • 不等超时,立即重传
    • SACK提高效率
  5. 流量控制

    • 防止接收方过载
    • 零窗口处理
    • 糊涂窗口综合症
  6. 拥塞控制

    • 慢启动(指数增长)
    • 拥塞避免(线性增长)
    • 快速恢复
    • 多种算法变体

重点回顾

TCP可靠传输 = 序列号 + 确认 + 重传 + 窗口

效率优化:
- 滑动窗口(批量发送)
- 快速重传(不等超时)
- SACK(选择性确认)

网络友好:
- 流量控制(保护接收方)
- 拥塞控制(保护网络)

明天预告

第17天:UDP协议详解

内容预览:

  • UDP报文格式
  • UDP vs TCP深入对比
  • UDP应用场景
  • UDP编程实战
  • 基于UDP实现可靠传输

继续加油! 🚀

今天我们学习了TCP如何实现可靠传输,这是TCP最核心的功能。理解这些机制不仅能帮助你更好地使用TCP,还能在遇到网络问题时快速定位原因!