TCP 发送窗口滑动 — P₁ · P₂ · P₃
1. 收到 ACK=31, win=20 → 构造发送窗口
接收方通告 ack=31, rwnd=20。发送方据此构造 swnd=20(暂不考虑 cwnd)。
已确认 0–30
允许发送 31–50
不允许 51+
P₁=P₂=31
P₃=51
20
swnd = P₃−P₁ = 51−31
0
已发未确认 = P₂−P₁
20
可用窗口 = P₃−P₂
/* 发送方收到 ACK=31, win=20 后 */
P1 = 31; // 窗口后沿
P2 = 31; // 尚未发送任何数据
P3 = 51; // 窗口前沿 = 31+20
send_window = P3 - P1 = 20;
inflight = P2 - P1 = 0;
usable = P3 - P2 = 20;
2. 发送了 31–41(11 字节)
发送方把 31–41 号字节封装在几个 TCP 报文段中发出。这些数据进入"已发送未确认"区。
已确认 0–30
已发未确认 31–41
可发 42–50
不允许 51+
P₁=31
P₂=42
P₃=51
20
swnd 不变
11
已发未确认 = 42−31
9
可用窗口 = 51−42
/* 发送 31–41 后 */
P1 = 31; // 后沿不动 —— 未收到新 ACK
P2 = 42; // 已发送到 41,下一位是 42
P3 = 51; // 前沿不动
/* 关键规则 */
// 后沿 P1:只在收到确认时前移
// 后沿 P1:绝不后移(已确认不可撤销)
// 前沿 P3:可能前移、不动、或(不推荐)后缩
3. 收到 ACK=34 → 窗口向前滑动 3 字节
确认号 34 表示 31–33 已按序到达。后沿 P₁ 前移到 34,`31–33` 可从发送缓存删除。前沿 P₃ 前移到 54。
已确认 0–33
已发未确认 34–41
可发 42–50
不允许 54+
P₁=34
P₂=42
P₃=54
20
swnd 不变
8
已发未确认 = 42−34
12
可用窗口 = 54−42
/* 收到 ACK=34 后 */
P1 = 34; // 后沿前移:31-33 已确认
P2 = 42; // P2 不动:尚未发送新数据
P3 = 54; // 前沿前移:P1+swnd = 34+20
/* 已确认的 31-33 可从缓存删除 */
// 小于 P1 的数据 = 已确认 = 可删除
4. 三个指针的核心规则总结
| P₁ 后沿 | 只有两种可能:不动(无新确认)或前移(收到新累积确认)。 绝不后移——已确认的字节不可撤销,数据可从发送缓存删除。 |
| P₂ 可用起点 | 指向下一个允许发送但尚未发送的字节。发送数据时 P₂ 前移;收到 ACK 时 P₂ 不动。 |
| P₃ 前沿 | 三种可能:前移(常态·确认扩大窗口)、不动(无变化或变化抵消)、后缩(接收方缩小窗口——TCP 强烈不推荐)。 |
/* 三个指针的精确含义(用于编程实现) */
/* < P1 : 已确认可删除 */
/* P1 ~ P2 : 已发送未确认(inflight) */
/* P2 ~ P3 : 允许发送但未发送(usable) */
/* > P3 : 不允许发送 */
swnd = P3 - P1; // 发送窗口总大小
inflight = P2 - P1; // 已发未确认
usable = P3 - P2; // 可用窗口/有效窗口