TCP 想做的事只有一件:把「不可靠的 IP」包装成「可靠的字节流」。 它用四件工具做到:序列号、确认应答、重传定时器、窗口。
6.1.3 讲了 TCP 的五个特征,这一节讲「这五个特征靠什么实现」。 5.8.4 的 ECN 会和这里的拥塞控制接上,不过那是 6.4.9 的事。
一、TCP 想解决什么
IP 只承诺「尽力而为」:可能丢、可能乱序、可能重复、可能迟到。 而绝大多数应用要的是「按顺序、一个字节不少」的一串数据。 TCP 的全部工作,就是在「尽力而为」之上造出「如约而至」。 注意它没有「让网络变可靠」:网络还是那个网络,丢包照样丢。 TCP 做的是「丢了能发现、发现能补」——终点站保证完整,路上照样乱。 这一点在理解「为什么 TCP 会很慢」时很关键:它的可靠性全是「靠等待换来的」, 等确认、等重传、等窗口,每一处都对应一段延迟。
二、四件工具
四件工具各管一段:
| 工具 | 解决什么 | 靠什么字段 |
|---|---|---|
| 序列号 | 乱序和重复 | seq |
| 确认应答 | 知道对方收到没 | ack |
| 重传定时器 | 丢了要补 | RTO |
| 窗口 | 别把对方淹了 | window |
第三行是「猜」出来的:发送方并不知道包丢了,只能靠「超时没收到确认」来推断。 所以 RTO 定得准不准,直接决定「反应快不快」——定太短会误重传,定太长会白等。 6.4.3 专门讲怎么算这个时间。 第四行管的是「对方」,不是「网络」:接收方的缓冲区有限,所以要说「我还能收多少」。 这一条在 6.4.8 会展开——它和「拥塞控制」是两套独立的机制,经常被混为一谈。
三、MSS 是什么
MSS 是「一个段最多能装多少数据」,它等于 MTU 减去两个头: IP 头 20 加 TCP 头 20,一共 40。 所以以太网上 MSS 就是 1460。 为什么要有这个概念:TCP 是字节流,理论上可以让 IP 层去分片。 但分片的代价很大(4.5.2 讲过:丢一片整个包作废), 所以 TCP 宁可「自己按 MSS 切好」,让每个段都能装进一个 IP 包。 这叫「避免分片」,是 TCP 的一个基本策略。 MSS 是「双方协商」出来的:握手时各报一个自己能接收的值,最后取小的那个。 所以「同一个连接里,两个方向的 MSS 可以不一样」——这看起来很怪,但确实是协议允许的。
四、实测两种链路的 MSS
同一段代码,连本机和连外网,MSS 差了几十倍: 因为 MSS 跟着 MTU 走,而回环接口的 MTU 特别大。 这提醒一件事:「TCP 的参数」不是常量,是「按介质算出来的」。 所以在机房内测出来的性能,搬到公网上往往不成立—— 不是代码变了,是「段的大小和往返时间」都变了。
五、动手 Demo:TCP 靠什么做到「可靠」
先摆四件工具,再实测两种链路的 MSS。 注意两者的差距有多大。
import socket
loop = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
loop.bind(('127.0.0.1', 0)); loop.listen(1)
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(loop.getsockname())
print('回环 MSS', c.getsockopt(socket.IPPROTO_TCP, socket.TCP_MAXSEG))
r = socket.create_connection(('www.baidu.com', 443), timeout=5)
print('外网 MSS', r.getsockopt(socket.IPPROTO_TCP, socket.TCP_MAXSEG))
实跑输出:
--------------------------------------------------------------------
TCP 靠什么做到「可靠」
--------------------------------------------------------------------
**TCP 不是「网络可靠」,而是「丢了能补上」**:
**它用四套机制把「不可靠的 IP」包装成「可靠的流」。**
机制 解决什么 靠什么字段
-----------------------------------------------------
**序列号** **乱序和重复** **seq**
**确认应答** **知道对方收到没** **ack**
**重传定时器** **丢了要补** **RTO**
**窗口** **别把对方淹了** **window**
**第三行是「猜」出来的**:**发送方并不知道包丢了,只能靠「超时没收到确认」推断。**
**所以 RTO 定得准不准,直接决定「反应快不快」**——**定太短会误重传,定太长会白等。**
**6.4.3 专门讲怎么算这个时间。**
**实测一下 MSS**(一个段最多能装多少数据):
**回环 MSS = 65483,外网 MSS = 1380**。
**差距这么大,是因为 MSS 跟着 MTU 走**:**回环接口的 MTU 有 64 KB 量级,以太网只有 1500。**
**所以「同一个协议,在不同链路上段长差几十倍」**——
**这也说明 TCP 的很多参数是「按介质调」的,不是常量。**
回环 65483、外网 1380,差了 47 倍:回环接口没有物理介质,MTU 由系统定得很大(6 万多), 而外网走的是 v6 加可能存在的隧道,所以 MSS 只有 1380。 外网那个 1380 值得算一下:1500 减 40 应该是 1460,现在是 1380,少了 80 字节, 正好是「一到两层隧道」的开销(5.7 算过四层是 80)。 所以「看到 MSS 比 1460 小」就能推断「路上有隧道或 PPPoE」。 最后一个提醒: 本机测出来的性能数字,几乎都不能代表真实网络——因为回环既不丢包、也没有延迟,MSS 还特别大。 所以「本地跑得飞快、上线就卡」是常态,不是异常。
30 秒实验
- 算一下:MTU 是 1500 时,MSS 是多少?
- 想一下:TCP 为什么不干脆让 IP 去分片?
- 想一下:外网 MSS 是 1380,说明路上大概有几层封装?
常见误区
- 以为「TCP 让网络变可靠了」。 网络照样丢包,TCP 只是「发现并补上」。
- 以为「MSS 是固定 1460」。 跟着 MTU 走,回环上是 6 万多。
- 以为「两个方向的 MSS 一样」。 各报各的,协议允许不对称。
自测三问(点开对答案)
1. TCP 的四件工具是什么? —— **序列号、确认应答、重传定时器、窗口**,每件管一个具体问题。 2. MSS 和 MTU 的关系? —— **MSS 等于 MTU 减去 IP 头和 TCP 头**,以太网上是 1500 减 40 等于 1460。 3. 为什么 TCP 要按 MSS 切段? —— **避免 IP 分片**:分片丢一片就整包作废,代价太大。下一节细看序列号和确认应答。
- ☐ (本节完,下一节 6.4.2 通过序列号与确认应答提高可靠性)