握手协议教学工作区 · 课程 0001 · 约 25 分钟 · 前置:无 · 2026-09-24

TCP 三次握手:把一次请求拆成四段

这节课的胜利:用 curl 的计时把一次 HTTPS 请求拆成 DNS / TCP / TLS / 首字节四段(真实数字来自你这台机器), 并说清三次握手发生在哪一段、为什么不能是两次、以及你那 6.68 秒的 TLS 段说明什么。

为什么是这一步

使命说这条线是"边缘函数工程师知识树的第一支柱:连接层原理"。 而连接层的第一个动作就是建立连接。大多数人能背出"三次握手",但说不出 "多出来的那一次到底防了什么" —— 这一节用你机器上的真实计时把这件事钉住。

最小知识:三条

  1. 三次握手 = SYN → SYN+ACK → ACK。它的目的不是"打招呼",而是双方各自确认两件事: 我能发、你能收;同时交换初始序列号(后面每个字节都要按序号确认,不交换就没法保证顺序与重传)。
  2. 为什么不能是两次?如果只发两次,服务端无法确认"客户端收到了我的 SYN+ACK"。 更关键的是:网络上可能有延迟很久的旧连接请求突然到达,服务端会为它建立一条客户端早已忘记的连接(半开)。 第三次 ACK 让服务端只在"客户端确实还在"时才认账。
  3. 四段计时的含义(curl 的 -w 变量): time_namelookup DNS 解析 → time_connect TCP 握手完成 → time_appconnect TLS 握手完成 → time_starttransfer 收到第一个字节。 每两段之间的差,就是那一层花的钱。

动手:量一次真实请求

在 Git Bash 里(输出是实测值,来自你这台机器 2026-09-24):

curl -s -o /dev/null -w "dns=%{time_namelookup}s tcp=%{time_connect}s tls=%{time_appconnect}s ttfb=%{time_starttransfer}s\n" https://example.com
# dns=0.005605s tcp=0.020753s tls=6.684226s ttfb=7.125429s

先读你自己的数字:

再看一眼"四次挥手"(顺带):连接关闭时为什么是四次?因为 TCP 是全双工 —— 一方的"我发完了"(FIN)与另一方的"我也发完了"(FIN)是两件独立的事,各自需要一次确认。 而握手可以合并(SYN+ACK 一次搞定),挥手不能。

加一道对比实验:把目标换成你本机的一个服务(比如 curl -w … http://127.0.0.1:8000,若没服务可用 python -m http.server 8000 起一个), 观察四段各自变成多少 —— 你会看到 DNS 与 TCP 都接近 0,这就是"局域网/本机"与"公网 + TLS"的差别。

自测(选项一样长,别从长度上猜)

1. 三次握手里,第二次(SYN+ACK)之后客户端还要发一次 ACK,为什么?

对。只有服务端确认"客户端确实收到了我的 SYN+ACK",它才认为连接真的建立 —— 这挡住的正是"延迟很久的旧连接请求"造成的半开连接。

2. time_connect 与 time_appconnect 的差是什么?

对。time_connect 是 TCP 握手完成(三次握手结束)的时刻;time_appconnect 是 TLS 握手完成。两者之差就是加密协商的成本 —— 你机器上这一段是 6.68 秒。

3. 连接关闭为什么要四次挥手?

对。TCP 是全双工:一方的"我发完了"(FIN)与另一方的"我也发完了"(FIN)是独立的两件事,各自需要确认。握手能把 SYN 与 ACK 合并,挥手不能。