【面试突击】深入理解 TCP 三次握手与 HTTP 协议演进

文章目录

  • [深入理解 TCP 三次握手与 HTTP 协议演进](#深入理解 TCP 三次握手与 HTTP 协议演进)

深入理解 TCP 三次握手与 HTTP 协议演进

📚 前言

作为后端开发工程师,理解网络协议是必备技能。本文将深入讲解 TCP 三次握手的序列号机制,以及 HTTP 协议从 1.0 到 2.0 的演进过程。


🔐 TCP 三次握手详解

三次握手流程图

复制代码
客户端 (Client)                          服务器 (Server)
   |                                         |
   | 1️⃣ SYN=1, seq=x                        |
   | --------------------------------------> |
   |   "我想连接,我的起始序列号是 x"          |
   |                                         |
   |                                         |
   | 2️⃣ SYN=1, ACK=1, seq=y, ack=x+1       |
   | <-------------------------------------- |
   |   "同意连接,我的起始序列号是 y"          |
   |   "我确认收到了你的 x"                   |
   |                                         |
   | 3️⃣ ACK=1, seq=x+1, ack=y+1            |
   | --------------------------------------> |
   |   "我确认收到了你的 y"                   |
   |                                         |
   |        【连接建立,开始传输数据】          |

第一次握手

复制代码
客户端发送:SYN=1, seq=x
  • seq=x:这是我的初始序列号,假设 x=1000
  • 意思:我后续发送的数据将从序列号 1000 开始编号

状态变化 :客户端进入 SYN_SENT 状态

第二次握手

复制代码
服务器发送:SYN=1, ACK=1, seq=y, ack=x+1
  • seq=y:这是我(服务器)的初始序列号,假设 y=5000
  • ack=x+1:我确认收到了你的 x,期待你下一个序列号是 x+1(1001)

意思

  • 我的数据将从 5000 开始编号
  • 我收到了你的 1000,下次请从 1001 开始

状态变化 :服务器进入 SYN_RECEIVED 状态

第三次握手

复制代码
客户端发送:ACK=1, seq=x+1, ack=y+1
  • seq=x+1:我按你的要求,现在用序列号 1001
  • ack=y+1:我确认收到了你的 y,期待你下一个序列号是 y+1(5001)

状态变化 :双方都进入 ESTABLISHED 状态,连接建立成功


💡 实际数据传输示例

假设:x=1000, y=5000

握手完成后传输数据:

复制代码
【客户端 → 服务器】发送 "Hello"(5字节)
seq=1001, data="Hello"
服务器回应:ack=1006  ← 表示"我收到了 1001-1005,下次请从 1006 开始"

【客户端 → 服务器】发送 "World"(5字节)
seq=1006, data="World"
服务器回应:ack=1011  ← 表示"我收到了 1006-1010,下次请从 1011 开始"

【服务器 → 客户端】发送 "OK"(2字节)
seq=5001, data="OK"
客户端回应:ack=5003  ← 表示"我收到了 5001-5002,下次请从 5003 开始"

完整通信流程

复制代码
步骤  方向              报文内容                          说明
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1    客户端 → 服务器    SYN=1, seq=1000                   请求连接
2    服务器 → 客户端    SYN=1, ACK=1, seq=5000, ack=1001  同意连接
3    客户端 → 服务器    ACK=1, seq=1001, ack=5001         确认连接
4    客户端 → 服务器    seq=1001, data="Hello"            发送数据
5    服务器 → 客户端    ack=1006                          确认收到
6    客户端 → 服务器    seq=1006, data="World"            发送数据
7    服务器 → 客户端    ack=1011                          确认收到
8    服务器 → 客户端    seq=5001, data="OK"               发送响应
9    客户端 → 服务器    ack=5003                          确认收到

🌐 HTTP 协议演进史

HTTP/1.0(1996年)

📋 主要特性
http 复制代码
GET /index.html HTTP/1.0
Host: www.example.com
Connection: close

核心特点

  • 短连接:每次请求都要建立新的 TCP 连接
  • 无状态:不保存客户端信息
  • 简单:易于实现
工作流程
复制代码
浏览器                                服务器
  |                                     |
  | 1. TCP 三次握手                     |
  | ----------------------------------> |
  |                                     |
  | 2. 发送 HTTP 请求                   |
  | ----------------------------------> |
  |                                     |
  | 3. 接收 HTTP 响应                   |
  | <---------------------------------- |
  |                                     |
  | 4. TCP 四次挥手(关闭连接)          |
  | <---------------------------------> |
  |                                     |
  | 5. 再次建立 TCP 连接(请求下一个资源) |
  | ----------------------------------> |
⚠️ 主要问题
  1. 连接无法复用:每个资源都需要独立的 TCP 连接
  2. 性能低下:频繁建立/关闭连接,握手开销大
  3. 队头阻塞:必须等待上一个请求完成
实际案例
复制代码
访问一个包含 1 个 HTML + 3 张图片的网页:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
连接1:  握手 → 请求 index.html → 响应 → 关闭
连接2: 握手 → 请求 image1.jpg → 响应 → 关闭
连接3: 握手 → 请求 image2.jpg → 响应 → 关闭
连接4: 握手 → 请求 image3.jpg → 响应 → 关闭

总共:4 次 TCP 握手 + 4 次挥手 = 56 次报文交互

HTTP/1.1(1999年)

📋 主要特性
http 复制代码
GET /index.html HTTP/1.1
Host: www.example.com
Connection: keep-alive

核心改进

  • 持久连接(Keep-Alive):默认复用 TCP 连接
  • 管道化(Pipelining):可同时发送多个请求
  • 分块传输(Chunked Transfer):支持流式传输
  • 缓存控制:更强大的 Cache-Control
  • Host 头部:支持虚拟主机
工作流程
复制代码
浏览器                                服务器
  |                                     |
  | 1. TCP 三次握手(只需一次)          |
  | ----------------------------------> |
  |                                     |
  | 2. 请求 index.html                  |
  | ----------------------------------> |
  | 3. 响应 index.html                  |
  | <---------------------------------- |
  |                                     |
  | 4. 请求 image1.jpg(复用连接)       |
  | ----------------------------------> |
  | 5. 响应 image1.jpg                  |
  | <---------------------------------- |
  |                                     |
  | 6. 请求 image2.jpg(复用连接)       |
  | ----------------------------------> |
  | 7. 响应 image2.jpg                  |
  | <---------------------------------- |
  |                                     |
  | ...  连接保持一段时间后关闭 ...        |
持久连接示例
复制代码
同样的场景(1 个 HTML + 3 张图片):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
连接1: 握手 → 请求1 → 响应1 → 请求2 → 响应2 
      → 请求3 → 响应3 → 请求4 → 响应4 → 关闭

总共:1 次 TCP 握手 + 1 次挥手 = 7 次报文交互
性能提升:(56-7)/56 = 87.5%
管道化(Pipelining)
复制代码
传统方式:
请求1 → 等待响应1 → 请求2 → 等待响应2 → 请求3

管道化:
请求1 → 请求2 → 请求3 → 响应1 → 响应2 → 响应3
⚠️ 仍存在的问题
  1. 队头阻塞(Head-of-Line Blocking)

    复制代码
    请求1(大文件 10MB)正在传输
    请求2(小文件 1KB)必须等待
    请求3(小文件 1KB)必须等待
  2. 明文传输:不安全(需要 HTTPS)

  3. 头部冗余:每次请求都发送重复的头部信息

  4. 并发限制:浏览器对同一域名的 TCP 连接数有限制(通常 6-8 个)


HTTP/2.0(2015年)

📋 核心特性

革命性改进

  • 二进制分帧:不再是纯文本协议
  • 多路复用:一个连接并发处理多个请求
  • 头部压缩(HPACK):减少传输数据量
  • 服务器推送:主动推送资源
  • 流优先级:控制资源加载顺序
1. 二进制分帧层
复制代码
HTTP/1.1(文本协议):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GET /index.html HTTP/1.1\r\n
Host: www.example.com\r\n
Connection: keep-alive\r\n
\r\n

HTTP/2.0(二进制协议):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+-----------------------------------------------+
|  Length (24) | Type (8) | Flags (8) |        |
+-+---------------------------------------------+
|R|                Stream ID (31)               |
+=+==============================================+
|                Frame Payload                  |
+-----------------------------------------------+
2. 多路复用(Multiplexing)
复制代码
HTTP/1.1(需要多个连接):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
连接1: |████ index.html ████|
连接2: |██ style.css ██|
连接3: |███ script.js ███|
连接4: |█ image1.jpg █|
连接5: |█ image2.jpg █|
连接6: |█ image3.jpg █|

HTTP/2.0(单一连接):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
单连接:  |██|█|██|█|██|█|████|█|██|█|
        └─┬─┴┬┴─┬─┴┬┴─┬─┴┬──┬─┴┬──┬─┴┬─
          1  2  1  3  1  2  1  3  2  3
          
流1: index.html
流2: style.css
流3: script.js
(并发传输,无阻塞)
3. 头部压缩(HPACK)
复制代码
HTTP/1.1(每次请求都发送完整头部):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
请求1:
GET /page1 HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0...
Accept: text/html...
Cookie: session=abc123... 
(约 500 字节)

请求2:
GET /page2 HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0... 
Accept: text/html...
Cookie: session=abc123...
(又是 500 字节,大部分重复!)

HTTP/2.0(头部压缩 + 索引):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
请求1: 
完整头部 (500 字节)
建立索引表

请求2:
: method:  GET
:path: /page2
[其他字段使用索引引用]
(仅约 50 字节,压缩率 90%!)
4. 服务器推送(Server Push)
复制代码
传统方式:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
浏览器:  请求 index.html
服务器:  返回 index.html
浏览器: 解析发现需要 style.css
浏览器: 请求 style.css
服务器: 返回 style.css
浏览器:  解析发现需要 script.js
浏览器: 请求 script.js
服务器:  返回 script.js

HTTP/2 服务器推送:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
浏览器: 请求 index.html
服务器: 返回 index.html
服务器: 主动推送 style.css(无需请求)
服务器: 主动推送 script.js(无需请求)
浏览器: 直接使用缓存的资源

代码示例(Node.js):

javascript 复制代码
const http2 = require('http2');
const fs = require('fs');

const server = http2.createSecureServer({
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem')
});

server.on('stream', (stream, headers) => {
  if (headers[':path'] === '/index.html') {
    // 主动推送 CSS
    stream.pushStream({ ': path': '/style.css' }, (err, pushStream) => {
      pushStream.respond({ ': status': 200 });
      pushStream.end(fs.readFileSync('style.css'));
    });
    
    // 返回 HTML
    stream.respond({ ':status': 200 });
    stream.end(fs.readFileSync('index.html'));
  }
});

server.listen(443);
5. 流优先级
复制代码
设置优先级:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
优先级 1 (最高): index.html
优先级 2:         style.css, script.js
优先级 3:        image1.jpg, image2.jpg
优先级 4 (最低): analytics.js

资源分配:
|█████ index.html █████|
|███ style.css ███|██ script.js ██|
|█ img1 █|█ img2 █|
|analytics.js|

📊 三代 HTTP 对比总结

特性 HTTP/1.0 HTTP/1.1 HTTP/2.0
连接方式 短连接 持久连接 多路复用
协议格式 文本 文本 二进制
头部压缩 ✅ HPACK
服务器推送
并发请求 1 个/连接 串行 并行
队头阻塞 严重 存在 大幅改善
传输效率
浏览器连接数 1 个 6-8 个 1 个

📝 总结

TCP 三次握手关键点

  1. x 和 y 是随机生成的初始序列号
  2. 握手过程同步双方序列号
  3. ack 始终等于对方 seq+1(或 +数据长度)
  4. 序列号用于保证数据有序、去重、重传

HTTP 演进关键点

  1. HTTP/1.0:一个请求一个连接,性能差
  2. HTTP/1.1:持久连接,解决连接复用问题
  3. HTTP/2.0:多路复用 + 二进制 + 压缩,性能飞跃
  4. HTTP/3.0:基于 QUIC,彻底解决队头阻塞

🔗 参考资料


觉得有帮助?点个赞再走吧!

如有问题欢迎在评论区讨论交流~

相关推荐
ベadvance courageouslyミ2 小时前
网络编程(三)HTTP
网络·网络协议·http
微爱帮监所写信寄信2 小时前
HTTPS技术架构与微爱帮监狱写信寄信小程序EV证书深度解析
网络协议·http·https·监狱寄信·微爱帮
Dream it possible!2 小时前
LeetCode 面试经典 150_回溯_单词搜索(104_79_C++_中等)
c++·leetcode·面试·回溯
阿蒙Amon2 小时前
C#每日面试题-进程和线程的区别
java·面试·c#
YJlio3 小时前
Sysinternals 文件工具学习笔记(12.12):常见踩坑场景、排障套路与面试问题
笔记·学习·面试
TracyCoder1233 小时前
告别明文传输:HTTPS 加密机制
网络协议·http·https
yaoh.wang3 小时前
力扣(LeetCode) 119: 杨辉三角 II - 解法思路
数据结构·python·算法·leetcode·面试·职场和发展·跳槽
Irene19914 小时前
HTTP 缓存详解
http·缓存
不想秃头的程序员4 小时前
JavaScript 中的深拷贝与浅拷贝详解
前端·面试