TCP 的适用面是「怕丢不怕慢」:凡是内容不能缺一个字节的,都选它。 代价是「每连一次都要付一个往返」,所以长连接和连接池才那么重要。
6.4.10 讲的是「怎么用得更省」,这一节看「谁在用、为什么用」。 6.1.4 讲了选型标准,这一节把它落到具体协议上。
一、哪些应用跑在 TCP 上
| 应用 | 端口 | 为什么用 TCP |
|---|---|---|
| HTTP/HTTPS | 80/443 | 少一个字节页面就坏 |
| SSH | 22 | 命令和输出必须按序 |
| SMTP/IMAP | 25/143 | 邮件不能丢字 |
| FTP | 20/21 | 文件要完整 |
| MySQL | 3306 | 语句和结果必须成套 |
五行其实是一个理由:「上层没有自己处理丢失的能力」。 网页不会自己重传,邮件客户端也不会,所以只能靠 TCP 兜住。 反过来,DNS 这种「一问一答」的协议就敢用 UDP—— 因为「没回就再问一次」这个逻辑太简单,不值得为它建连接、维护状态、还要处理半关闭。
二、握手成本有多高
一次 TCP 连接,在传数据之前要先付一个往返: 客户端发 SYN,服务端回 SYN 加 ACK,客户端再 ACK。 数据要等第三个包之后才能开始走。 同城几毫秒、跨省几十毫秒、跨洋一百多毫秒: 所以「打开一个国外网站慢」有一部分不是带宽问题,而是「握手就花掉了两三百毫秒」。 而 TLS 还要再来一到两个往返,所以「首次访问」的延迟是「握手加握手」。 这就是长连接和连接池存在的理由: 「连一次用很多次」把「每请求一个往返」摊薄成「每连接一个往返」。 HTTP/1.1 的 keep-alive、HTTP/2 的多路复用、数据库连接池,全都是同一个思路的不同实现。
三、实测与观察
本机连一个外网站点,握手耗时通常在几十毫秒量级: 这个数就是「纯网络往返」,不包含任何数据传输。 所以「同一个请求,第二次比第一次快」很常见—— 不是因为「缓存了数据」,而是「连接还在,不用再握手」。 这也解释了一个常见困惑: 「为什么用工具测速很快,但打开网页感觉慢」—— 测速测的是「大流量吞吐」,网页感受的是「很多次小交互的往返」。 两者的瓶颈完全不同。
四、动手 Demo:哪些应用跑在 TCP 上
把常见应用的端口和理由列出来,再实测一次握手耗时。 这个耗时就是「连接的成本」。
import socket, time
t0 = time.perf_counter()
s = socket.create_connection(('www.baidu.com', 443), timeout=5)
print('握手 %.2f ms' % ((time.perf_counter() - t0) * 1000))
s.close()
实跑输出:
--------------------------------------------------------------------
哪些应用跑在 TCP 上
--------------------------------------------------------------------
**TCP 的适用面是「怕丢不怕慢」**,**所以「凡是内容不能缺一个字节的」都选它。**
应用 端口 为什么用 TCP
-----------------------------------------------------------
**HTTP/HTTPS** **80/443** **少一个字节页面就坏**
**SSH** **22** **命令和输出必须按序**
**SMTP/IMAP** **25/143** **邮件不能丢字**
**FTP** **20/21** **文件要完整**
**MySQL** **3306** **语句和结果必须成套**
**五行其实是一个理由**:**「上层没有自己处理丢失的能力」**。
**网页不会自己重传,邮件客户端也不会**,**所以只能靠 TCP 兜住。**
**反过来,DNS 这种「一问一答」的协议就敢用 UDP**——
**因为「没回就再问一次」这个逻辑太简单,不值得为它建连接。**
**实测一次 TCP 握手要多久**:
**连 www.baidu.com:443 用了 65.66 毫秒**,本地出口端口 57371。
**这几十毫秒就是「三次握手」的全部代价**:**一个往返用来协商,之后才开始传数据。**
**所以「短连接」的成本不只是带宽,还有「每连一次都要付一个往返」**——
**这就是 HTTP 长连接、连接池存在的理由。**
这个数字每次都不一样:它受路由、当前网络状况、DNS 缓存影响,
所以「测一次就下结论」是不靠谱的,要看多次的分布。
注意这里包含了「域名解析」的时间:create_connection 内部会先解析域名,
所以这个数比「纯 TCP 握手」略大。
要测纯握手,得先解析出地址,再连地址。
最后一个观察:「首包延迟」和「吞吐」是两个指标。
网页、游戏看首包延迟,下载、备份看吞吐,优化方向完全不同。
所以「网络优化」这句话必须说清「优化哪一项」。
30 秒实验
- 算一下:跨洋往返 200 毫秒,握手加 TLS 两个往返一共多少?
- 想一下:为什么「第二次请求更快」?
- 想一下:测速很快但网页慢,可能是什么原因?
常见误区
- 以为「TCP 应用都很慢」。 慢的是「握手和等待」,长连接之后差别不大。
- 以为「连接池只是省资源」。 它主要省的是「往返时间」,不只是内存。
- 以为「测速快就等于上网快」。 测的是吞吐,网页体验看的是「多次小交互的延迟」。
自测三问(点开对答案)
1. 为什么网页、邮件、数据库都用 TCP? —— **上层没有自己处理丢失的能力**,内容缺一个字节就坏了。 2. 一次 TCP 握手的成本是多少? —— **一个往返**:同城几毫秒,跨洋一百多毫秒。 3. 连接池主要省什么? —— **省掉「每请求一次握手」**,把往返成本摊薄到每条连接上。下一节讲几个「非主流」的传输层协议。
- ☐ (本节完,下一节 6.5.1 UDP-Lite)