一次完整握手分五步:打招呼、选参数、发证书、验身份并算密钥、开始加密传数据。 TLS 1.3 把中间两步并成一趟,所以只要一次往返就能发数据。
前四节把零件都拆开看过了,这一节按顺序装回去,并且量出每一步花多少时间。
一、五个阶段
- 客户端发 ClientHello:支持的版本、套件列表、一个随机数、以及密钥交换用的份额。
- 服务端回 ServerHello:选定的版本与套件、自己的随机数、自己的份额。
- 服务端发 Certificate:证书链,客户端顺着它追到受信根。
- 双方各自用两份份额算出同一份会话密钥,互发 Finished 校验握手没被改。
- 之后所有 HTTP 报文都装进 TLS 记录里加密传输。 第 4 步那句「算出同一份」是整件事的巧妙之处:双方各出一个秘密,只用公开的数交换, 最后算出同一个结果。中间人看得见交换的全过程,却算不出那个结果——这就是 Diffie-Hellman 的本事。
二、实测的耗时构成
Demo 真连 www.example.com,分三段计时:DNS 解析 5.4 毫秒、TCP 三次握手 1236.0 毫秒、
TLS 握手 478.8 毫秒,合计 1720.2 毫秒。
TCP 那段特别长,是因为到这台服务器的网络本身就慢(跨洋),不是协议的问题。
这个数只能当「本机到该站的实测」看,不能当通用结论。
谈成的是 TLSv1.3、套件 TLS_AES_256_GCM_SHA384,证书名 example.com 与 *.example.com,
有效期到 2026-12-25。
第一次请求 41 字节、收 937 字节、耗时 451.7 毫秒;同一条连接上再要一次,199.3 毫秒。
差的这 250 毫秒就是「省掉三次握手」省下来的——这也是长连接的价值。
三、TLS 1.3 为什么快
TLS 1.2 的握手要两趟往返:先谈参数,再换密钥。 TLS 1.3 把这两趟并成一趟,客户端甚至在收到 ServerHello 之后就能直接发数据(0-RTT 复用)。 它还砍掉了一批老旧算法(RSA 密钥交换、CBC 模式、RC4、SHA-1),套件从几十个缩到五个。 这不是「功能变少」,是「不给选错的机会」。 会话复用也值得一提:第二次连同一个站点,可以用上次的 PSK 直接恢复,省掉证书验证那一大段。 Demo 里那 199 毫秒虽然还是新连接,但没有再付证书和密钥交换的钱。
四、动手 Demo:分三段计时,再把同一条连接用第二次
真连一次公网站点,分别计 DNS、TCP、TLS 三段耗时;打印谈成的版本、套件、证书名; 然后发一个请求、再在同一条连接上发第二个,比较两次往返。
t0 = time.time()
infos = socket.getaddrinfo(host, 443, proto=socket.IPPROTO_TCP)
t_dns = time.time() - t0
t0 = time.time()
s = socket.create_connection((ip, 443), timeout=8)
t_tcp = time.time() - t0
ctx = ssl.create_default_context()
ctx.set_alpn_protocols([u'http/1.1'])
t0 = time.time()
t = ctx.wrap_socket(s, server_hostname=host) # 握手在这里发生
t_tls = time.time() - t0
实跑输出:
--------------------------------------------------------------------
一次完整握手,分几个阶段
--------------------------------------------------------------------
目标 www.example.com,解析到 172.66.147.243
分阶段计时(单位毫秒):
DNS 解析 5.4 域名换 IP
TCP 三次握手 1236.0 建立连接
TLS 握手 478.8 协商密钥 + 验证证书
合计 1720.2
握手谈成了什么:
协议版本 TLSv1.3
加密套件 TLS_AES_256_GCM_SHA384
套件所属协议 TLSv1.3
会话是否复用 否
证书里的名字 example.com、*.example.com
证书有效期至 Dec 25 22:56:35 2026 GMT
第一次请求的往返时间:
请求 41 字节,收到 937 字节,耗时 451.7 毫秒
同一条连接上再要一次(省掉 DNS、TCP、TLS 三段):
收到 937 字节,耗时 199.3 毫秒
第二次数值明显更小:这就是长连接和 HTTPS 一起用的意义——
握手只付一次,后面的请求只付往返。
把五个阶段按顺序排一遍,就是书上那张图:
1. 客户端发 ClientHello:支持的版本、套件、一个随机数、密钥交换的份额
2. 服务端回 ServerHello:选定的版本与套件、自己的随机数、自己的份额
3. 服务端发 Certificate:证书链,客户端顺着它追到受信根
4. 双方各自用份额算出同一份会话密钥,互发 Finished 校验握手没被改
5. 之后所有 HTTP 报文都装进 TLS 记录里加密传输
TLS 1.3 把 2 和 3 并成一趟,所以只需一次往返就能开始发数据;
TLS 1.2 要两趟。这就是 1.3 更快的主要原因。
三段耗时 5.4/1236.0/478.8 毫秒,合计 1720.2 毫秒。TCP 那一段长是网络距离造成的,不是协议慢。
谈成 TLSv1.3 加 TLS_AES_256_GCM_SHA384;
证书覆盖 example.com 和 *.example.com,到期日 2026-12-25。
第一次请求 451.7 毫秒,第二次 199.3 毫秒,省掉的就是握手。
注意第二次收的字节数一样多(都是 937),差的全在时间上。
这也解释了「为什么首屏慢、点进去快」:首屏要付三次握手,点进去的请求复用同一条连接,只付往返。
30 秒实验
- 把 host 换成一个离你近的站,看 TCP 那段的毫秒数掉多少。
- 在同一条连接上连发五次,把平均耗时和第一次比。
- 想一想:为什么 0-RTT 复用有「重放攻击」的隐患?
常见误区
- 「TLS 握手要两趟往返」——那是 1.2,1.3 只要一趟。
- 「HTTPS 每发一个请求都要重新握手」——长连接只握手一次。
- 「握手慢是加密算得慢」——主要是往返次数和网络延迟,加密计算只占几毫秒。
自测三问(点开对答案)
1. 完整握手的五个阶段按顺序是什么? —— ClientHello、ServerHello、Certificate、算密钥并 Finished、加密传数据。 2. TLS 1.3 相比 1.2 快在哪? —— 把两次往返并成一次,并砍掉一批老旧算法。 3. 同一条连接上第二个请求为什么快得多? —— 省掉了 DNS、TCP 三次握手和 TLS 握手,只剩一次往返。第七章到这儿收尾。下一章换个话题:谁在使用 HTTP——从浏览器到各种设备。
- ☐ (本章完,下一节 8.1 何为认证)