Appearance
HTTP
导航目录
基础篇
缓存篇
跨域篇
安全篇
协议演进篇
HTTP 协议特点
核心概念
HTTP(超文本传输协议)是应用层协议,基于 TCP/IP,采用请求-响应模型,是 Web 通信的基石。其几个核心特性决定了它的行为方式。
| 特点 | 说明 |
|---|---|
| 简单快速 | 只需传送请求方法和路径(GET/POST/HEAD 等),服务器程序规模小、速度快 |
| 灵活 | 可传输任意类型数据,类型由 Content-Type 标记 |
| 无连接 | 每次连接只处理一个请求,处理完即断开(HTTP/1.1 起用长连接优化) |
| 无状态 | 协议对事务处理无记忆能力,需借助 Cookie/Session/Token 维持状态 |
| 支持 B/S、C/S | 适用于浏览器-服务器、客户端-服务器架构 |
无状态的解决
由于 HTTP 无状态,登录态等场景需要额外机制:Cookie(客户端存储)、Session(服务端存储 + Cookie 携带 sessionId)、Token(如 JWT,服务端无状态校验)。
HTTP 报文的组成部分
核心概念
HTTP 报文分请求报文与响应报文,均由「起始行 + 头部 + 空行 + 主体」四部分组成。空行是头部与主体的分隔标志,不可省略。
请求报文
GET /hu.jpg HTTP/1.1 // 请求行:方法 + 资源路径 + 协议版本
Host: example.com // 请求头部:附加信息
User-Agent: Mozilla/5.0 ...
// 空行(必须,标志头部结束)
name=zhangsan&age=18 // 请求主体(GET 通常为空)响应报文
HTTP/1.1 200 OK // 状态行:协议版本 + 状态码 + 状态短语
Content-Type: application/json // 响应头部
Content-Length: 27
// 空行
{ "code": 0, "data": {} } // 响应主体说明
Host 指出请求目的地;User-Agent 标识客户端类型,是浏览器检测的基础;即使主体为空,头部后的空行也必须存在。
HTTP 状态码
核心概念
状态码是服务器对请求处理结果的三位数字表示,首位数字标识类别。掌握常见状态码有助于快速定位问题。
| 类别 | 含义 |
|---|---|
| 1xx | 指示信息:请求已接收,继续处理 |
| 2xx | 成功:请求已被成功接收、理解、处理 |
| 3xx | 重定向:需进一步操作以完成请求 |
| 4xx | 客户端错误:请求语法错误或无法实现 |
| 5xx | 服务端错误:服务器未能实现合法请求 |
常见状态码
| 状态码 | 含义 |
|---|---|
| 200 OK | 请求成功 |
| 201 Created | 资源已创建(POST/PUT 成功) |
| 204 No Content | 成功但无返回内容 |
| 206 Partial Content | 部分内容(断点续传、分片) |
| 301 Moved Permanently | 永久重定向(SEO 会转移权重) |
| 302 Found | 临时重定向 |
| 304 Not Modified | 资源未修改,使用协商缓存 |
| 400 Bad Request | 请求语法错误 |
| 401 Unauthorized | 未认证(需登录) |
| 403 Forbidden | 已认证但无权限 |
| 404 Not Found | 资源不存在 |
| 500 Internal Server Error | 服务器内部错误 |
| 502 Bad Gateway | 网关错误(上游服务异常) |
| 503 Service Unavailable | 服务暂时不可用(过载/维护) |
| 504 Gateway Timeout | 网关超时 |
易混辨析
301 vs 302:前者永久(浏览器会缓存新地址);后者临时。401 vs 403:前者"你是谁"(未登录),后者"你没权限"(已登录但被拒)。
GET、POST 区别
核心概念
GET 与 POST 是最常用的两种请求方法,本质都是基于 TCP 的 HTTP 请求,区别更多是「语义约定」与「浏览器/服务器实现习惯」,而非协议强制。
| 维度 | GET | POST |
|---|---|---|
| 语义 | 获取资源(读) | 提交数据(写) |
| 参数位置 | URL 查询字符串 | 请求主体 body |
| 参数长度 | 受 URL 长度限制(浏览器/服务器约束) | 理论无限制 |
| 缓存 | 会被浏览器主动缓存 | 默认不缓存 |
| 幂等性 | 幂等(多次请求结果一致) | 非幂等 |
| 安全性 | 参数暴露在 URL,易被记录 | 参数在 body,相对隐蔽 |
| 数据包 | 通常一个 TCP 包 | 部分浏览器分两次发(先 header 后 body) |
安全性澄清
POST 并非真正"安全"——body 同样是明文。真正的安全依赖 HTTPS 加密,而非选用 POST。
长连接与短连接
核心概念
HTTP 的长/短连接本质是底层 TCP 连接的复用与否。长连接减少了反复建立/关闭 TCP 连接(三次握手四次挥手)的开销。
| 类型 | 说明 |
|---|---|
| 短连接 | HTTP/1.0 默认。每次 HTTP 操作都新建一次 TCP 连接,请求结束即断开。页面中每个资源都要重新建连 |
| 长连接 | HTTP/1.1 默认。通过 Connection: keep-alive 复用 TCP 连接,页面加载完后连接不立即关闭,后续请求继续复用 |
要点
Keep-Alive 有超时时间(可在 Nginx/Apache 配置),并非永久保持;长连接需客户端与服务端都支持。HTTP 的长短连接实质是 TCP 的长短连接。
HTTP 缓存架构图
核心概念
HTTP 缓存分为「强缓存」与「协商缓存」。浏览器请求资源时先查强缓存,命中则直接用本地副本(不发请求);未命中再走协商缓存,向服务器询问资源是否更新。

整体流程
- 浏览器请求资源,先检查强缓存(
Cache-Control/Expires)。 - 强缓存有效 → 直接使用本地缓存,状态码
200 (from disk/memory cache),不发请求。 - 强缓存失效 → 发起请求进入协商缓存,携带
If-Modified-Since/If-None-Match。 - 服务器判断资源是否变化:未变化返回
304,用本地缓存;变化返回200+ 新资源。
内存缓存 vs 磁盘缓存
from memory cache:读取快、随进程释放(如刷新时的图片/脚本);from disk cache:持久化到磁盘,容量大、速度稍慢。
Last-Modified & ETag
核心概念
两者都是协商缓存的校验依据。Last-Modified 基于文件最后修改时间,ETag 基于文件内容生成的唯一标识(哈希)。ETag 优先级更高,用于弥补 Last-Modified 的精度缺陷。
| 对比项 | Last-Modified | ETag |
|---|---|---|
| 依据 | 文件最后修改时间 | 文件内容指纹(哈希等) |
| 请求头 | If-Modified-Since | If-None-Match |
| 响应头 | Last-Modified | ETag |
| 精度 | 秒级(1 秒内多次修改无法识别) | 内容级,精确 |
| 缺陷 | 内容不变仅时间变时会误判 | 计算有性能开销 |
校验流程
① 首次请求 → 响应头带 Last-Modified / ETag
② 再次请求 → 请求头带 If-Modified-Since / If-None-Match
③ 服务器比对:未变 → 304 Not Modified;已变 → 200 + 新资源与新标识注意
若同时存在 ETag 和 Last-Modified,服务器会优先校验 ETag。周期性重写但内容不变的文件(如构建产物),应依赖 ETag 避免误判。
强缓存与协商缓存
核心概念
强缓存不与服务器交互,直接用本地缓存;协商缓存需向服务器发请求确认。二者是「先强后协商」的层级关系。
| 类型 | 强缓存 | 协商缓存 |
|---|---|---|
| 是否发请求 | 否 | 是(询问是否更新) |
| 相关头 | Cache-Control、Expires | ETag/If-None-Match、Last-Modified/If-Modified-Since |
| 命中状态码 | 200 (from cache) | 304 Not Modified |
Cache-Control 常用值
| 值 | 含义 |
|---|---|
max-age=秒 | 缓存有效时长(相对时间,优先级高于 Expires) |
no-cache | 不用强缓存,每次走协商缓存 |
no-store | 完全不缓存 |
public | 可被浏览器、代理服务器缓存 |
private | 仅浏览器可缓存 |
Expires vs Cache-Control
Expires 是 HTTP/1.0 产物,值为绝对时间(受客户端时间影响不可靠);Cache-Control: max-age 是 HTTP/1.1 相对时间,优先级更高,推荐使用。
刷新操作对缓存的影响
核心概念
不同的刷新方式对缓存的处理策略不同,理解这点有助于调试缓存问题。
| 操作 | 强缓存 | 协商缓存 |
|---|---|---|
| 地址栏回车 / 前进后退 | 生效 | 生效 |
| 普通刷新(F5) | 失效 | 生效 |
| 强制刷新(Ctrl+F5) | 失效 | 失效 |
说明
普通刷新会跳过强缓存,直接发协商请求(多为 304);强制刷新会带 Cache-Control: no-cache,强、协商缓存都失效,全部资源重新拉取。
同源策略
核心概念
同源策略(Same-Origin Policy)是浏览器最核心的安全机制。「同源」指协议、域名、端口三者完全相同。它限制一个源的文档/脚本与另一个源的资源交互,防止 XSS、CSRF 等攻击。
| 对比 URL | 是否同源 | 原因 |
|---|---|---|
http://a.com/a.js vs http://a.com/b.js | 同源 | 协议、域名、端口一致 |
http://a.com vs https://a.com | 不同源 | 协议不同 |
http://a.com vs http://b.com | 不同源 | 域名不同 |
http://a.com:80 vs http://a.com:8080 | 不同源 | 端口不同 |
记忆
同源三要素:协议 + 域名 + 端口,缺一不可。子域名(a.com vs www.a.com)也算不同源。
跨域请求限制
核心概念
同源策略限制的是「读取」跨域资源的能力,而非「发送」请求。请求通常能发出去,只是响应被浏览器拦截。
同源策略主要限制以下三类行为:
- DOM 访问受限:无法读取不同源 iframe 的 DOM。
- 数据读取受限:无法读取不同源的 Cookie、LocalStorage、IndexedDB。
- 网络请求受限:AJAX(XHR/fetch)请求可以发出,但响应会被浏览器拦截,JS 无法读取。
常见误解
跨域请求其实已到达服务器并被处理(后端能收到),只是浏览器基于同源策略拦截了响应,导致前端拿不到数据。所以跨域是浏览器行为,不是服务端行为。
不受同源策略限制的情况
核心概念
部分标签天然允许跨域加载资源,这也是 JSONP 等早期跨域方案的原理基础。
| 场景 | 说明 |
|---|---|
<img> | 图片跨域加载(打点统计常用) |
<script> | 脚本跨域加载(JSONP 原理) |
<link> | CSS、字体等跨域加载 |
<video> / <audio> | 媒体资源跨域 |
| 跳转/表单提交 | 页面跳转、<form> 提交不受限 |
JSONP 原理
利用 <script> 可跨域的特性,前端定义回调函数,服务端返回 callback(data) 形式的脚本执行。缺点:只支持 GET、安全性差,现已被 CORS 取代。
CORS 跨域完整流程
核心概念
CORS(跨域资源共享)是 W3C 标准的跨域方案,通过服务端设置响应头告诉浏览器「允许该源访问」。请求分为「简单请求」与「非简单请求(需预检)」两类。
简单请求
同时满足以下条件即为简单请求,浏览器直接发送并在请求头带 Origin:
- 方法为
GET/POST/HEAD。 - 请求头仅限安全字段(
Accept、Content-Type等)。 Content-Type仅为text/plain、multipart/form-data、application/x-www-form-urlencoded。
① 浏览器请求
GET /api/data HTTP/1.1
Origin: http://a.com
② 服务器响应(关键 CORS 头)
Access-Control-Allow-Origin: http://a.com // 或 *
Access-Control-Allow-Credentials: true // 允许带 Cookie 时非简单请求(预检)
不满足简单请求条件(如 PUT/DELETE、Content-Type: application/json、自定义头),浏览器会先发 OPTIONS 预检请求:
① 预检请求(浏览器自动发起)
OPTIONS /api/data HTTP/1.1
Origin: http://a.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
② 预检响应
Access-Control-Allow-Origin: http://a.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400 // 预检结果缓存时间
③ 预检通过后,才发送真实请求服务端设置示例(Node.js / Express)
js
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "http://a.com");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.header("Access-Control-Allow-Credentials", "true"); // 允许携带 Cookie
if (req.method === "OPTIONS") return res.sendStatus(204); // 预检直接返回
next();
});携带 Cookie 的限制
当 Access-Control-Allow-Credentials: true 时,Access-Control-Allow-Origin 不能为 *,必须指定具体源;前端也需设置 xhr.withCredentials = true 或 fetch(url, { credentials: 'include' })。
跨域预检请求优化
核心概念
非简单请求每次都会先发一次 OPTIONS 预检,增加了一次往返开销。可通过 Access-Control-Max-Age 缓存预检结果,减少重复预检。
Nginx 配置示例
nginx
location /api/ {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Max-Age 86400; # 预检结果缓存 1 天
# 预检请求直接返回 204,不转发到后端
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://backend;
}优化要点
- 用
Access-Control-Max-Age缓存预检结果(浏览器有效期内不再预检)。 - 尽量让请求满足「简单请求」条件,避免触发预检。
- 在网关/Nginx 层统一处理 CORS,避免每个后端服务重复配置。
HTTP 对比 HTTPS
核心概念
HTTPS = HTTP + SSL/TLS。它在 HTTP 与 TCP 之间加了一层加密(TLS),解决了 HTTP 明文传输带来的窃听、篡改、冒充问题。
| 对比项 | HTTP | HTTPS |
|---|---|---|
| 传输 | 明文 | 加密(TLS) |
| 端口 | 80 | 443 |
| 证书 | 无需 | 需 CA 证书 |
| 安全性 | 易被窃听/篡改 | 加密 + 身份认证 + 完整性校验 |
| 性能 | 无加密开销 | 握手有额外开销(可用会话复用优化) |
HTTPS 三大保障
加密性(防窃听)、完整性(防篡改)、身份认证(防冒充)。三者共同构成安全通信基础。
对称加密
核心概念
对称加密指加密和解密使用同一把密钥。特点是速度快、效率高,适合加密大量数据。常见算法:AES、DES、3DES。
明文 --(密钥 K 加密)--> 密文 --(密钥 K 解密)--> 明文核心痛点
对称加密的难点在于密钥分发:通信双方如何在不安全的网络中安全地交换这把密钥?若密钥在传输中被截获,加密即失效。这正是需要非对称加密的原因。
非对称加密
核心概念
非对称加密使用一对密钥:公钥(公开)和私钥(保密)。公钥加密的数据只能用私钥解密,反之亦然。解决了密钥分发问题,但速度慢。常见算法:RSA、ECC。
公钥加密 → 私钥解密 (用于加密数据,只有私钥持有者能解)
私钥加密 → 公钥解密 (用于数字签名,验证发送方身份)HTTPS 的组合方案
HTTPS 结合两者:用非对称加密安全地传递对称密钥,之后的通信用对称加密(快)。即"非对称协商密钥 + 对称传输数据",兼顾安全与性能。
为什么有非对称加密还需要 CA 证书
核心概念
非对称加密解决了密钥分发,但无法解决"公钥是否可信"的问题——中间人可以伪造公钥。CA(证书颁发机构)通过数字证书为公钥的归属做权威背书。
没有 CA 的漏洞(中间人攻击)
客户端 →(索要公钥)→ 中间人(掉包成自己的公钥)→ 服务器
之后客户端用的是中间人的公钥,通信全被中间人解密/篡改CA 证书的作用
- 服务器把公钥等信息交给 CA,CA 用自己的私钥签名生成证书。
- 浏览器内置了受信任 CA 的公钥,可验证证书签名的真伪。
- 验证通过即确认「这个公钥确实属于该网站」,中间人无法伪造(没有 CA 私钥)。
关键
CA 证书本质是「用 CA 私钥对网站公钥的签名」。浏览器信任链:根 CA → 中间 CA → 网站证书。任何一环校验失败都会提示"不安全"。
HTTPS 的 TLS 握手过程
核心概念
TLS 握手是 HTTPS 建立安全连接的关键步骤,目的是验证身份并协商出对称密钥。以下为经典 RSA 密钥交换流程(TLS 1.2)。
text
客户端 服务器
| 1. Client Hello(TLS版本、加密套件、随机数1) |
| ───────────────────────────────────────────────► |
| 2. Server Hello(选定版本、加密套件、随机数2) |
| ◄─────────────────────────────────────────────── |
| 3. 发送 CA 证书(含服务器公钥) |
| ◄─────────────────────────────────────────────── |
| [4. 客户端校验证书合法性] |
| 5. 用公钥加密预主密钥发送 |
| ───────────────────────────────────────────────► |
| [双方用 随机数1+随机数2+预主密钥 生成会话密钥] |
| 6. Finished(用会话密钥加密) |
| ───────────────────────────────────────────────► |
| 7. Finished(用会话密钥加密) |
| ◄─────────────────────────────────────────────── |
| [之后用对称会话密钥加密通信] |核心步骤说明
- 客户端发送支持的加密套件与随机数(Client Random)。
- 服务器选定加密套件,回传随机数(Server Random)+ CA 证书。
- 客户端校验证书,生成"预主密钥"(Pre-Master Secret),用服务器公钥加密后发送。
- 双方根据两个随机数 + 预主密钥,各自计算出相同的会话密钥(对称密钥)。
- 之后所有通信用会话密钥对称加密。
TLS 1.3 优化
TLS 1.3 简化握手,仅需 1-RTT(甚至 0-RTT 会话恢复),并废弃不安全的算法,改用 ECDHE 前向安全的密钥交换,握手更快更安全。
HTTPS 中间人攻击
核心概念
中间人攻击(MITM)指攻击者插入通信双方之间,冒充双方转发/篡改数据。HTTPS 通过 CA 证书体系防御,但在特定场景仍可能被攻破。
攻击方式
- 证书伪造:攻击者伪造证书,若浏览器无内置对应 CA 则会告警。
- SSL 剥离:把 HTTPS 降级为 HTTP,诱导明文通信。
- 诱导安装根证书:让用户手动信任攻击者的根证书(抓包工具如 Charles/Fiddler 原理)。
防御手段
| 手段 | 说明 |
|---|---|
| CA 证书校验 | 浏览器验证证书链,非法证书告警 |
| HSTS | 强制浏览器只用 HTTPS,防降级 |
| 证书锁定(Pinning) | App 内固定合法证书指纹 |
| 不随意信任根证书 | 避免安装来源不明的根证书 |
抓包原理
Charles/Fiddler 抓 HTTPS 包,本质就是"合法的中间人"——需要你手动安装它的根证书,让浏览器信任其伪造的证书,从而解密流量。这也说明保护根证书信任列表的重要性。
HTTP 2.0 的优势
核心概念
HTTP/2 基于 SPDY,在不改变 HTTP 语义的前提下大幅提升性能,核心是「二进制分帧」,解决了 HTTP/1.1 的性能瓶颈。
| 特性 | 说明 |
|---|---|
| 二进制分帧 | 报文拆成二进制帧传输,解析更高效、无歧义 |
| 多路复用 | 同一 TCP 连接并行传输多个请求/响应,解决队头阻塞(应用层) |
| 头部压缩(HPACK) | 压缩冗余头部,减少传输量 |
| 服务器推送 | 服务器可主动推送客户端可能需要的资源 |
| 请求优先级 | 可为流设置优先级,重要资源优先传输 |
对比 HTTP/1.1
HTTP/1.1 靠「多个 TCP 连接 + 长连接 + 管线化」优化,但受浏览器并发连接数限制(约 6 个)且有队头阻塞。HTTP/2 单连接即可高效并发。
HTTP 2 的多路复用
核心概念
多路复用(Multiplexing)指在一个 TCP 连接上同时发送多个请求和响应,互不干扰。这是 HTTP/2 相比 HTTP/1.1 的最大改进。
实现原理
- 流(Stream):一个双向字节流,对应一个请求/响应对,有唯一 ID。
- 消息(Message):一个完整的请求或响应,由多个帧组成。
- 帧(Frame):最小传输单位,带有所属流的标识。
HTTP/1.1:请求需排队(一个连接同一时间一个请求)
连接 1: [请求 A]--------[请求 B]--------[请求 C]
HTTP/2:多个流的帧交错在同一连接传输
连接 1: [A 帧][B帧][A 帧][C帧][B 帧][C帧] → 按流 ID 重组效果
多路复用消除了 HTTP/1.1 的「应用层队头阻塞」,一个连接即可并发大量请求,减少连接建立开销与资源占用。
队头阻塞问题
核心概念
队头阻塞(Head-of-Line Blocking)指队列中第一个数据被阻塞,导致后续数据全部等待。HTTP 演进史很大程度就是解决队头阻塞的历史。
| 层级 | 队头阻塞 | 是否解决 |
|---|---|---|
| HTTP/1.1 应用层 | 一个连接同一时间只能处理一个请求,前一个不完成后面排队 | HTTP/2 多路复用解决 |
| TCP 传输层 | TCP 需按序交付,丢一个包后面所有包都要等重传 | HTTP/2 仍存在,HTTP/3 用 QUIC 解决 |
HTTP/2 的遗留问题
HTTP/2 解决了应用层队头阻塞,但底层仍是 TCP。一旦某个 TCP 包丢失,整个连接上所有流都要等待重传——这就是 TCP 层队头阻塞。这也是 HTTP/3 改用 UDP(QUIC)的根本原因。
HTTP 3 与 QUIC
核心概念
HTTP/3 最大变革是传输层从 TCP 换成基于 UDP 的 QUIC 协议,彻底解决了 TCP 层队头阻塞,并优化了连接建立速度。
| 特性 | 说明 |
|---|---|
| 基于 UDP(QUIC) | 在 UDP 上自行实现可靠传输、拥塞控制 |
| 无 TCP 队头阻塞 | 各流独立,一个流丢包不影响其他流 |
| 0-RTT / 1-RTT 建连 | 合并传输握手与 TLS 握手,首次 1-RTT,恢复 0-RTT |
| 连接迁移 | 用 Connection ID 标识连接,切换网络(WiFi↔4G)不断连 |
| 内置 TLS 1.3 | 加密是 QUIC 的一部分,默认安全 |
HTTP/1.1 → HTTP/2 → HTTP/3
TCP TCP QUIC(UDP)
明文/TLS TLS 内置 TLS1.3
应用层阻塞 TCP 层阻塞 无队头阻塞连接迁移
QUIC 用 Connection ID 而非「IP+端口」标识连接,因此手机从 WiFi 切到 4G 时连接不中断,视频/直播场景体验更好。
TCP 和 UDP 区别
核心概念
TCP 与 UDP 都是传输层协议。TCP 面向连接、可靠有序;UDP 无连接、不可靠但高效。选择取决于对可靠性与实时性的权衡。
| 对比项 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接(三次握手) | 无连接 |
| 可靠性 | 可靠(确认、重传、排序) | 不可靠(尽力而为) |
| 顺序 | 保证有序 | 不保证 |
| 速度 | 较慢(开销大) | 快(开销小) |
| 头部开销 | 20 字节起 | 8 字节 |
| 传输方式 | 字节流 | 数据报 |
| 适用场景 | HTTP、文件传输、邮件 | 视频直播、DNS、游戏、QUIC |
记忆
TCP 像"打电话"(先建连、可靠有序);UDP 像"发短信/广播"(发出即走,不管对方收没收到)。
TCP 三次握手与四次挥手
核心概念
三次握手用于建立连接,确认双方收发能力正常;四次挥手用于断开连接,确保双方数据都发送完毕。
三次握手(建立连接)
text
客户端 服务器
| 1. SYN=1, seq=x(我要连你) |
| ───────────────────────────────────────► |
| 2. SYN=1, ACK=1, seq=y, ack=x+1(我也要连你)|
| ◄─────────────────────────────────────── |
| 3. ACK=1, ack=y+1(确认,开始通信) |
| ───────────────────────────────────────► |为什么是三次? 两次无法确认「客户端的接收能力」和「服务端的发送能力」。三次才能保证双方收发能力都正常,防止已失效的连接请求突然到达导致误连。
四次挥手(断开连接)
text
客户端 服务器
| 1. FIN=1, seq=u(我没数据要发了) |
| ─────────────────────────────────► |
| 2. ACK=1, ack=u+1(知道了) |
| ◄───────────────────────────────── |
| 3. FIN=1, seq=w(我也发完了) |
| ◄───────────────────────────────── |
| 4. ACK=1, ack=w+1(确认,等 2MSL) |
| ─────────────────────────────────► |为什么是四次? 服务端收到 FIN 后可能还有数据要发,所以「确认」和「关闭」分两步发送,比握手多一次。
TIME_WAIT 状态
客户端最后需等待 2MSL(最大报文段生存时间)才关闭,目的是:① 确保最后的 ACK 到达服务端;② 让本次连接的旧报文在网络中消散,避免影响新连接。