3.
-## POP3/IMAP:邮件接收的协议
+## POP3/IMAP:邮件接收协议
-这两个协议没必要多做阐述,只需要了解 **POP3 和 IMAP 两者都是负责邮件接收的协议** 即可(二者也是基于 TCP 协议)。另外,需要注意不要将这两者和 SMTP 协议搞混淆了。**SMTP 协议只负责邮件的发送,真正负责接收的协议是 POP3/IMAP。**
+**POP3 和 IMAP 都是用于接收邮件的协议**,二者也都是基于 TCP 的应用层协议。
-IMAP 协议是比 POP3 更新的协议,它在功能和性能上都更加强大。IMAP 支持邮件搜索、标记、分类、归档等高级功能,而且可以在多个设备之间同步邮件状态。几乎所有现代电子邮件客户端和服务器都支持 IMAP。
+
-## FTP:文件传输协议
+需要注意的是:**SMTP 主要负责邮件发送和转发,POP3/IMAP 主要负责用户从邮箱服务器读取邮件。**
-**FTP 协议** 基于 TCP 协议,是一种用于在计算机之间传输文件的协议,可以屏蔽操作系统和文件存储方式。
+POP3 的设计比较简单,常见模式是把邮件从服务器下载到本地。它适合单设备收信,但多设备同步体验较差。
-FTP 是基于客户—服务器(C/S)模型而设计的,在客户端与 FTP 服务器之间建立两个连接。如果我们要基于 FTP 协议开发一个文件传输的软件的话,首先需要搞清楚 FTP 的原理。关于 FTP 的原理,很多书籍上已经描述的非常详细了:
+IMAP 是更现代、更常用的邮件接收协议。它支持在服务器端管理邮件,能够同步邮件状态,比如已读、未读、删除、归档、文件夹分类等。因此,如果你同时在手机、电脑、网页端查看同一个邮箱,IMAP 的体验通常会更好。
-> FTP 的独特的优势同时也是与其它客户服务器程序最大的不同点就在于它在两台通信的主机之间使用了两条 TCP 连接(其它客户服务器应用程序一般只有一条 TCP 连接):
->
-> 1. 控制连接:用于传送控制信息(命令和响应)
-> 2. 数据连接:用于数据传送;
+简单对比一下:
+
+| 协议 | 主要用途 | 特点 |
+| ---- | -------------- | -------------------------------- |
+| POP3 | 接收邮件 | 偏下载到本地,多设备同步能力弱 |
+| IMAP | 接收和管理邮件 | 支持多设备同步、搜索、标记、归档 |
+| SMTP | 发送和转发邮件 | 负责邮件投递链路 |
+
+## FTP:文件传输协议
+
+**FTP(File Transfer Protocol,文件传输协议)** 是一种基于 TCP 的应用层协议,用于在客户端和服务器之间传输文件。
+
+
+
+FTP 采用客户端-服务器模型。它比较特殊的一点是:FTP 通常会建立两条 TCP 连接。
+
+> FTP 与很多应用层协议不同,它在客户端和服务器之间使用两条连接:
>
-> 这种将命令和数据分开传送的思想大大提高了 FTP 的效率。
+> 1. **控制连接**:用于传输命令和响应,例如登录、切换目录、删除文件等。
+> 2. **数据连接**:用于真正传输文件内容或目录列表。
+
+这种将命令和数据分开传输的设计,能够让控制命令和文件数据互不干扰。
+
+
+
+FTP 有主动模式(PORT)和被动模式(PASV)两种数据连接方式:
+
+- **主动模式**:客户端通过控制连接告诉服务端自己监听的端口,服务端再主动连接客户端的这个端口建立数据连接。由于服务端要主动连接客户端,如果客户端在 NAT 或防火墙后面,很容易连接失败。
+- **被动模式**:客户端请求服务端开放一个数据端口,然后由客户端主动连接服务端的数据端口。因为连接方向仍然是客户端到服务端,更容易穿过 NAT 和防火墙,所以实际生产环境中更常用被动模式。
+
+注意:FTP 本身是不安全的。它默认不会加密传输内容,用户名、密码和文件数据都可能被窃听或篡改。
+
+因此,传输敏感文件时不建议使用普通 FTP,可以选择:
+
+- **SFTP**:基于 SSH 的安全文件传输协议。
+- **FTPS**:在 FTP 基础上增加 TLS/SSL 加密。
+
+其中,SFTP 和 FTPS 名字相似,但不是同一个协议。SFTP 基于 SSH,FTPS 是 FTP over TLS。
+
+## Telnet:远程登录协议
+
+**Telnet** 是一种基于 TCP 的远程登录协议,默认端口是 23。它允许用户通过终端远程登录到服务器,并在远程机器上执行命令。
+
+Telnet 最大的问题是:**明文传输**。
+
+
+
+用户名、密码、命令内容和返回结果都不会加密,攻击者如果能监听网络流量,就可能直接看到敏感信息。
+
+
+
+因此,Telnet 现在已经很少用于真正的远程管理。实际生产环境中,通常使用 SSH 替代 Telnet。
+
+## SSH:安全的网络传输协议
+
+**SSH(Secure Shell)** 是一种基于 TCP 的安全网络协议,默认端口是 22。它通过加密和认证机制,为远程登录、命令执行和文件传输提供安全保障。
+
+
+
+SSH 最经典的用途是登录远程服务器:
+
+```bash
+ssh user@server_ip
+```
+
+除了远程登录,SSH 还支持:
+
+- 远程执行命令
+- 端口转发
+- 隧道代理
+- X11 转发
+- 基于 SFTP 或 SCP 的安全文件传输
+
+SSH 使用客户端-服务器模型。SSH Server 监听客户端连接请求,SSH Client 发起连接。双方会先协商加密算法,并通过密钥交换生成后续通信使用的对称加密密钥。之后的通信内容都会被加密传输。
+
+
+
+需要注意的是,SSH 的安全性不仅来自加密传输,也来自身份认证机制。常见认证方式包括:
+
+- 密码认证
+- 公钥认证
+- 多因素认证
+
+实际生产环境中,更推荐使用公钥认证,并关闭弱密码登录。
+
+## RTP:实时传输协议
+
+**RTP(Real-time Transport Protocol,实时传输协议)** 是一种用于传输音频、视频等实时数据的协议。它通常运行在 UDP 之上。在 TCP/IP 分层模型中,UDP 之上就是应用层,所以 RTP 按分层规则被归入应用层。但它承担的职责(序列号、时间戳、同步、质量反馈)更接近传输层功能,RFC 3550 也说它“通常会集成到应用处理中,而不是作为独立层实现”。
+
+
+
+RTP 主要用在语音通话、视频会议、直播等实时场景。它本身不保证可靠传输,也不保证按时到达,而是通过序列号、时间戳等信息帮助接收端进行排序、同步和播放控制。虽然也存在 RTP over TCP 的封装方式(如 RFC 4571),但更多用于穿越防火墙或兼容特定协议栈等特殊场景,实际实时音视频场景中 RTP 仍以 UDP 为主。
+
+RTP 通常会和 RTCP 配合使用:
+
+- **RTP**:负责传输实时音视频数据。
+- **RTCP(RTP Control Protocol)**:负责传输控制信息和统计信息,比如丢包率、延迟、抖动等。
+
+在 WebRTC 中,RTP/RTCP 是实时音视频传输的重要基础。WebRTC 还会结合 SRTP 加密、拥塞控制、抖动缓冲、NACK、FEC 等机制,提升实时通信的安全性和质量。
+
+需要注意的是,RTP 本身不负责资源预留,也不保证实时传输质量。它提供的是实时媒体传输的基础能力,具体的质量控制需要依赖上层机制配合完成。
+
+## DNS:域名系统
+
+**DNS(Domain Name System,域名系统)** 用于解决域名和 IP 地址之间的映射问题。
-
+
-注意 ⚠️:FTP 是一种不安全的协议,因为它在传输过程中不会对数据进行加密。因此,FTP 传输的文件可能会被窃听或篡改。建议在传输敏感数据时使用更安全的协议,如 SFTP(一种基于 SSH 协议的安全文件传输协议,用于在网络上安全地传输文件)。
+我们访问网站时,通常输入的是域名,例如:
-## Telnet:远程登陆协议
+```text
+www.javaguide.cn
+```
-**Telnet 协议** 基于 TCP 协议,用于通过一个终端登陆到其他服务器。Telnet 协议的最大缺点之一是所有数据(包括用户名和密码)均以明文形式发送,这有潜在的安全风险。这就是为什么如今很少使用 Telnet,而是使用一种称为 SSH 的非常安全的网络传输协议的主要原因。
+但网络通信实际需要的是 IP 地址。DNS 的作用就是把域名解析成对应的 IP 地址。
-
+DNS 通常使用 UDP,默认端口是 53。之所以优先使用 UDP,是因为大多数 DNS 查询和响应都比较小,不需要 TCP 三次握手,响应更快。
-## SSH:安全的网络传输协议
+在早期 DNS 规范中,UDP DNS 消息大小限制为 512 字节(不包含 IP 和 UDP 头)。如果响应过大,服务器会设置截断标志,客户端再通过 TCP 重试。
-**SSH(Secure Shell)** 基于 TCP 协议,通过加密和认证机制实现安全的访问和文件传输等业务。
+后来 EDNS0 扩展了 DNS over UDP 的报文大小上限,使 DNS 能承载更大的响应,比如 DNSSEC 相关数据。但如果响应超过协商的 UDP 大小,或者发生区域传送(DNS 服务器之间同步整域数据,普通域名解析几乎不会触发),仍然会使用 TCP。
-SSH 的经典用途是登录到远程电脑中执行命令。除此之外,SSH 也支持隧道协议、端口映射和 X11 连接。借助 SFTP 或 SCP 协议,SSH 还可以传输文件。
+现代网络中还出现了更安全的 DNS 方案,比如:
-SSH 使用客户端-服务器模型,默认端口是 22。SSH 是一个守护进程,负责实时监听客户端请求,并进行处理。大多数现代操作系统都提供了 SSH。
+- **DoH(DNS over HTTPS)**
+- **DoT(DNS over TLS)**
-
+它们的目的都是减少 DNS 明文查询带来的隐私和安全问题。
-## RTP:实时传输协议
+## 常见应用层协议端口总结
-RTP(Real-time Transport Protocol,实时传输协议)通常基于 UDP 协议,但也支持 TCP 协议。它提供了端到端的实时传输数据的功能,但不包含资源预留存、不保证实时传输质量,这些功能由 WebRTC 实现。
+| 协议 | 默认端口 | 传输层协议 | 主要用途 |
+| --------- | --------------------------------: | ---------- | ---------------------- |
+| HTTP | 80 | TCP | Web 页面访问 |
+| HTTPS | 443 | TCP / QUIC | 加密 Web 访问 |
+| WebSocket | 80 / 443 | TCP | 双向实时通信 |
+| SMTP | 25 / 465 / 587 | TCP | 邮件发送和转发 |
+| POP3 | 110 / 995 | TCP | 邮件接收 |
+| IMAP | 143 / 993 | TCP | 邮件接收和同步 |
+| FTP | 20 / 21 | TCP | 文件传输 |
+| SSH | 22 | TCP | 安全远程登录和文件传输 |
+| Telnet | 23 | TCP | 明文远程登录 |
+| DNS | 53 | UDP / TCP | 域名解析 |
+| RTP | 动态端口(偶数),RTCP 用相邻奇数 | UDP 为主 | 实时音视频传输 |
-RTP 协议分为两种子协议:
+这里 HTTPS 写成 TCP / QUIC,是因为传统 HTTPS 通常基于 TLS over TCP,而 HTTP/3 场景下会基于 QUIC。
-- **RTP(Real-time Transport Protocol,实时传输协议)**:传输具有实时特性的数据。
-- **RTCP(RTP Control Protocol,RTP 控制协议)**:提供实时传输过程中的统计信息(如网络延迟、丢包率等),WebRTC 正是根据这些信息处理丢包
+## 小结
-## DNS:域名系统
+这篇文章只做了常见应用层协议的快速梳理,没有展开到协议报文和具体实现细节。
-DNS(Domain Name System,域名管理系统)基于 UDP 协议,用于解决域名和 IP 地址的映射问题。
+复习时可以重点记住几个容易混淆的点:
-
+- HTTP 是应用层协议,HTTP/1.1 和 HTTP/2 通常基于 TCP,HTTP/3 基于 QUIC。
+- HTTP/1.1 通过 Keep-Alive 复用 TCP 连接,HTTP/2 在一个 TCP 连接上做多路复用,HTTP/3 基于 QUIC 缓解 TCP 队头阻塞。
+- WebSocket 通过 HTTP 升级建立连接,之后支持双向通信。
+- SMTP 负责邮件发送和服务器间转发,POP3/IMAP 负责用户收取邮件。
+- SMTP 常见端口包括 25、587、465,分别对应服务器间转发、客户端提交和隐式 TLS 提交等场景。
+- FTP 有主动模式和被动模式,实际生产环境中被动模式更常见。
+- FTP、SFTP、FTPS 不是一回事,FTP 明文传输,SFTP 基于 SSH,FTPS 基于 TLS。
+- Telnet 明文传输,不适合生产环境远程管理,实际更常用 SSH。
+- DNS 通常基于 UDP,但响应过大、发生截断、区域传送等场景下也会使用 TCP。
+- RTP 运行在 UDP 之上,按分层规则归入应用层,但职责更接近传输层;RTP 用偶数端口,配套 RTCP 用相邻奇数端口。
## 参考
-- 《计算机网络自顶向下方法》(第七版)
-- RTP 协议介绍:
+- 《计算机网络:自顶向下方法》(第七版)
+- RTP 协议介绍:
+- RFC 6455:The WebSocket Protocol
+- RFC 9110:HTTP Semantics
+- RFC 8446:TLS 1.3
+- RFC 9000:QUIC
+- RFC 3550:RTP: A Transport Protocol for Real-Time Applications
+- RFC 4571:Framing Real-time Transport Protocol (RTP) and RTP Control Protocol (RTCP) Packets over Connection-Oriented Transport
+- RFC 6891:Extension Mechanisms for DNS (EDNS(0))
diff --git a/docs/cs-basics/network/arp.md b/docs/cs-basics/network/arp.md
index c4ece76011c..d48a0d1a128 100644
--- a/docs/cs-basics/network/arp.md
+++ b/docs/cs-basics/network/arp.md
@@ -1,19 +1,25 @@
---
title: ARP 协议详解(网络层)
+description: 讲解 ARP 的地址解析机制与报文流程,结合 ARP 表与广播/单播详解常见攻击与防御策略。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: ARP,地址解析,IP到MAC,广播问询,单播响应,ARP表,欺骗
---
-每当我们学习一个新的网络协议的时候,都要把他结合到 OSI 七层模型中,或者是 TCP/IP 协议栈中来学习,一是要学习该协议在整个网络协议栈中的位置,二是要学习该协议解决了什么问题,地位如何?三是要学习该协议的工作原理,以及一些更深入的细节。
+IP 地址负责网络层寻址,但数据帧在局域网里真正转发时,还需要知道下一跳设备的 MAC 地址。
-**ARP 协议**,可以说是在协议栈中属于一个**偏底层的、非常重要的、又非常简单的**通信协议。
+ARP 要解决的就是这个转换问题:**已知目标 IP 地址,如何找到对应的 MAC 地址**。它看起来简单,却串起了网络层和链路层,也是理解局域网通信、网关转发和 ARP 欺骗的基础。
-开始阅读这篇文章之前,你可以先看看下面几个问题:
+这篇文章主要回答几个问题:
-1. **ARP 协议在协议栈中的位置?** ARP 协议在协议栈中的位置非常重要,在理解了它的工作原理之后,也很难说它到底是网络层协议,还是链路层协议,因为它恰恰串联起了网络层和链路层。国外的大部分教程通常将 ARP 协议放在网络层。
-2. **ARP 协议解决了什么问题,地位如何?** ARP 协议,全称 **地址解析协议(Address Resolution Protocol)**,它解决的是网络层地址和链路层地址之间的转换问题。因为一个 IP 数据报在物理上传输的过程中,总是需要知道下一跳(物理上的下一个目的地)该去往何处,但 IP 地址属于逻辑地址,而 MAC 地址才是物理地址,ARP 协议解决了 IP 地址转 MAC 地址的一些问题。
-3. **ARP 工作原理?** 只希望大家记住几个关键词:**ARP 表、广播问询、单播响应**。
+1. ARP 在协议栈中处于什么位置?
+2. ARP 如何通过广播问询、单播响应完成地址解析?
+3. ARP 表有什么作用,缓存过期会带来什么影响?
+4. 常见 ARP 攻击是怎么发生的,又该如何防御?
## MAC 地址
@@ -21,7 +27,7 @@ tag:
MAC 地址的全称是 **媒体访问控制地址(Media Access Control Address)**。如果说,互联网中每一个资源都由 IP 地址唯一标识(IP 协议内容),那么一切网络设备都由 MAC 地址唯一标识。
-
+
可以理解为,MAC 地址是一个网络设备真正的身份证号,IP 地址只是一种不重复的定位方式(比如说住在某省某市某街道的张三,这种逻辑定位是 IP 地址,他的身份证号才是他的 MAC 地址),也可以理解为 MAC 地址是身份证号,IP 地址是邮政地址。MAC 地址也有一些别称,如 LAN 地址、物理地址、以太网地址等。
@@ -46,7 +52,7 @@ ARP 的工作原理将分两种场景讨论:
### 同一局域网内的 MAC 寻址
-假设当前有如下场景:IP 地址为`137.196.7.23`的主机 A,想要给同一局域网内的 IP 地址为`137.196.7.14`主机 B,发送 IP 数据报文。
+假设当前有如下场景:IP 地址为 `137.196.7.23` 的主机 A,想要给同一局域网内的 IP 地址为 `137.196.7.14` 主机 B,发送 IP 数据报文。
> 再次强调,当主机发送 IP 数据报文时(网络层),仅知道目的地的 IP 地址,并不清楚目的地的 MAC 地址,而 ARP 协议就是解决这一问题的。
diff --git a/docs/cs-basics/network/computer-network-xiexiren-summary.md b/docs/cs-basics/network/computer-network-xiexiren-summary.md
index ac7e5d18b97..4fe3b930f2c 100644
--- a/docs/cs-basics/network/computer-network-xiexiren-summary.md
+++ b/docs/cs-basics/network/computer-network-xiexiren-summary.md
@@ -1,11 +1,25 @@
---
title: 《计算机网络》(谢希仁)内容总结
+description: 基于《计算机网络》教材的学习笔记,梳理术语与分层模型等核心知识点,便于期末复习与面试巩固。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: 计算机网络,谢希仁,术语,分层模型,链路,主机,教材总结
---
-本文是我在大二学习计算机网络期间整理, 大部分内容都来自于谢希仁老师的[《计算机网络》第七版](https://www.elias.ltd/usr/local/etc/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%88%E7%AC%AC7%E7%89%88%EF%BC%89%E8%B0%A2%E5%B8%8C%E4%BB%81.pdf)这本书。为了内容更容易理解,我对之前的整理进行了一波重构,并配上了一些相关的示意图便于理解。
+这篇笔记来自我大二学习计算机网络时的整理,大部分内容参考谢希仁老师的[《计算机网络》第七版](https://www.elias.ltd/usr/local/etc/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%88%E7%AC%AC7%E7%89%88%EF%BC%89%E8%B0%A2%E5%B8%8C%E4%BB%81.pdf)。
+
+计算机网络教材内容很散:术语、分层、链路、路由、运输层、应用层都要串起来看。为了复习起来更顺,我对原来的笔记做了一次重构,并补充了一些示意图。
+
+这篇文章主要回答几个问题:
+
+1. 计算机网络里常见基础术语分别是什么意思?
+2. OSI、TCP/IP 分层模型分别如何理解?
+3. 链路层、网络层、运输层、应用层各自解决什么问题?
+4. 复习《计算机网络》这本书时,哪些概念最容易混淆?

@@ -15,41 +29,41 @@ tag:
### 1.1. 基本术语
-1. **结点 (node)**:网络中的结点可以是计算机,集线器,交换机或路由器等。
-2. **链路(link )** : 从一个结点到另一个结点的一段物理线路。中间没有任何其他交点。
+1. **结点(node)**:网络中的结点可以是计算机,集线器,交换机或路由器等。
+2. **链路(link)**:从一个结点到另一个结点的一段物理线路。中间没有任何其他交点。
3. **主机(host)**:连接在因特网上的计算机。
4. **ISP(Internet Service Provider)**:因特网服务提供者(提供商)。
-
+ 
5. **IXP(Internet eXchange Point)**:互联网交换点 IXP 的主要作用就是允许两个网络直接相连并交换分组,而不需要再通过第三个网络来转发分组。
-
+ 
-https://labs.ripe.net/Members/fergalc/ixp-traffic-during-stratos-skydive
+ https://labs.ripe.net/Members/fergalc/ixp-traffic-during-stratos-skydive
-6. **RFC(Request For Comments)**:意思是“请求评议”,包含了关于 Internet 几乎所有的重要的文字资料。
+6. **RFC(Request For Comments)**:意思是“请求评议”,包含了关于 Internet 几乎所有的重要的文字资料。
7. **广域网 WAN(Wide Area Network)**:任务是通过长距离运送主机发送的数据。
8. **城域网 MAN(Metropolitan Area Network)**:用来将多个局域网进行互连。
9. **局域网 LAN(Local Area Network)**:学校或企业大多拥有多个互连的局域网。
-
+ 
-http://conexionesmanwman.blogspot.com/
+ http://conexionesmanwman.blogspot.com/
-10. **个人区域网 PAN(Personal Area Network)**:在个人工作的地方把属于个人使用的电子设备用无线技术连接起来的网络 。
+10. **个人区域网 PAN(Personal Area Network)**:在个人工作的地方把属于个人使用的电子设备用无线技术连接起来的网络。
-
+ 
-https://www.itrelease.com/2018/07/advantages-and-disadvantages-of-personal-area-network-pan/
+ https://www.itrelease.com/2018/07/advantages-and-disadvantages-of-personal-area-network-pan/
-12. **分组(packet )**:因特网中传送的数据单元。由首部 header 和数据段组成。分组又称为包,首部可称为包头。
-13. **存储转发(store and forward )**:路由器收到一个分组,先检查分组是否正确,并过滤掉冲突包错误。确定包正确后,取出目的地址,通过查找表找到想要发送的输出端口地址,然后将该包发送出去。
+11. **分组(packet)**:因特网中传送的数据单元。由首部 header 和数据段组成。分组又称为包,首部可称为包头。
+12. **存储转发(store and forward)**:路由器收到一个分组,先检查分组是否正确,并过滤掉冲突包错误。确定包正确后,取出目的地址,通过查找表找到想要发送的输出端口地址,然后将该包发送出去。
-
+ 
-14. **带宽(bandwidth)**:在计算机网络中,表示在单位时间内从网络中的某一点到另一点所能通过的“最高数据率”。常用来表示网络的通信线路所能传送数据的能力。单位是“比特每秒”,记为 b/s。
-15. **吞吐量(throughput )**:表示在单位时间内通过某个网络(或信道、接口)的数据量。吞吐量更经常地用于对现实世界中的网络的一种测量,以便知道实际上到底有多少数据量能够通过网络。吞吐量受网络的带宽或网络的额定速率的限制。
+13. **带宽(bandwidth)**:在计算机网络中,表示在单位时间内从网络中的某一点到另一点所能通过的“最高数据率”。常用来表示网络的通信线路所能传送数据的能力。单位是“比特每秒”,记为 b/s。
+14. **吞吐量(throughput)**:表示在单位时间内通过某个网络(或信道、接口)的数据量。吞吐量更经常地用于对现实世界中的网络的一种测量,以便知道实际上到底有多少数据量能够通过网络。吞吐量受网络的带宽或网络的额定速率的限制。
### 1.2. 重要知识点总结
@@ -76,31 +90,31 @@ tag:
1. **数据(data)**:运送消息的实体。
2. **信号(signal)**:数据的电气的或电磁的表现。或者说信号是适合在传输介质上传输的对象。
-3. **码元( code)**:在使用时间域(或简称为时域)的波形来表示数字信号时,代表不同离散数值的基本波形。
-4. **单工(simplex )**:只能有一个方向的通信而没有反方向的交互。
-5. **半双工(half duplex )**:通信的双方都可以发送信息,但不能双方同时发送(当然也就不能同时接收)。
+3. **码元(code)**:在使用时间域(或简称为时域)的波形来表示数字信号时,代表不同离散数值的基本波形。
+4. **单工(simplex)**:只能有一个方向的通信而没有反方向的交互。
+5. **半双工(half duplex)**:通信的双方都可以发送信息,但不能双方同时发送(当然也就不能同时接收)。
6. **全双工(full duplex)**:通信的双方可以同时发送和接收信息。
-
+ 
7. **失真**:失去真实性,主要是指接受到的信号和发送的信号不同,有磨损和衰减。影响失真程度的因素:1.码元传输速率 2.信号传输距离 3.噪声干扰 4.传输媒体质量
-
+ 
8. **奈氏准则**:在任何信道中,码元的传输的效率是有上限的,传输速率超过此上限,就会出现严重的码间串扰问题,使接收端对码元的判决(即识别)成为不可能。
9. **香农定理**:在带宽受限且有噪声的信道中,为了不产生误差,信息的数据传输速率有上限值。
10. **基带信号(baseband signal)**:来自信源的信号。指没有经过调制的数字信号或模拟信号。
11. **带通(频带)信号(bandpass signal)**:把基带信号经过载波调制后,把信号的频率范围搬移到较高的频段以便在信道中传输(即仅在一段频率范围内能够通过信道),这里调制过后的信号就是带通信号。
-12. **调制(modulation )**:对信号源的信息进行处理后加到载波信号上,使其变为适合在信道传输的形式的过程。
-13. **信噪比(signal-to-noise ratio )**:指信号的平均功率和噪声的平均功率之比,记为 S/N。信噪比(dB)=10\*log10(S/N)。
-14. **信道复用(channel multiplexing )**:指多个用户共享同一个信道。(并不一定是同时)。
+12. **调制(modulation)**:对信号源的信息进行处理后加到载波信号上,使其变为适合在信道传输的形式的过程。
+13. **信噪比(signal-to-noise ratio)**:指信号的平均功率和噪声的平均功率之比,记为 S/N。信噪比(dB)=10\*log10(S/N)。
+14. **信道复用(channel multiplexing)**:指多个用户共享同一个信道。(并不一定是同时)。
-
+ 
-15. **比特率(bit rate )**:单位时间(每秒)内传送的比特数。
+15. **比特率(bit rate)**:单位时间(每秒)内传送的比特数。
16. **波特率(baud rate)**:单位时间载波调制状态改变的次数。针对数据信号对载波的调制速率。
17. **复用(multiplexing)**:共享信道的方法。
-18. **ADSL(Asymmetric Digital Subscriber Line )**:非对称数字用户线。
+18. **ADSL(Asymmetric Digital Subscriber Line)**:非对称数字用户线。
19. **光纤同轴混合网(HFC 网)**:在目前覆盖范围很广的有线电视网的基础上开发的一种居民宽带接入网
### 2.2. 重要知识点总结
@@ -125,11 +139,11 @@ tag:
#### 2.3.2. 几种常用的信道复用技术
-1. **频分复用(FDM)**:所有用户在同样的时间占用不同的带宽资源。
+1. **频分复用(FDM)**:所有用户在同样的时间占用不同的带宽资源。
2. **时分复用(TDM)**:所有用户在不同的时间占用同样的频带宽度(分时不分频)。
-3. **统计时分复用 (Statistic TDM)**:改进的时分复用,能够明显提高信道的利用率。
-4. **码分复用(CDM)**:用户使用经过特殊挑选的不同码型,因此各用户之间不会造成干扰。这种系统发送的信号有很强的抗干扰能力,其频谱类似于白噪声,不易被敌人发现。
-5. **波分复用( WDM)**:波分复用就是光的频分复用。
+3. **统计时分复用(Statistic TDM)**:改进的时分复用,能够明显提高信道的利用率。
+4. **码分复用(CDM)**:用户使用经过特殊挑选的不同码型,因此各用户之间不会造成干扰。这种系统发送的信号有很强的抗干扰能力,其频谱类似于白噪声,不易被敌人发现。
+5. **波分复用(WDM)**:波分复用就是光的频分复用。
#### 2.3.3. 几种常用的宽带接入技术,主要是 ADSL 和 FTTx
@@ -145,16 +159,16 @@ tag:
2. **数据链路(data link)**:把实现控制数据运输的协议的硬件和软件加到链路上就构成了数据链路。
3. **循环冗余检验 CRC(Cyclic Redundancy Check)**:为了保证数据传输的可靠性,CRC 是数据链路层广泛使用的一种检错技术。
4. **帧(frame)**:一个数据链路层的传输单元,由一个数据链路层首部和其携带的封包所组成协议数据单元。
-5. **MTU(Maximum Transfer Uint )**:最大传送单元。帧的数据部分的的长度上限。
-6. **误码率 BER(Bit Error Rate )**:在一段时间内,传输错误的比特占所传输比特总数的比率。
-7. **PPP(Point-to-Point Protocol )**:点对点协议。即用户计算机和 ISP 进行通信时所使用的数据链路层协议。以下是 PPP 帧的示意图:
+5. **MTU(Maximum Transfer Uint)**:最大传送单元。帧的数据部分的长度上限。
+6. **误码率 BER(Bit Error Rate)**:在一段时间内,传输错误的比特占所传输比特总数的比率。
+7. **PPP(Point-to-Point Protocol)**:点对点协议。即用户计算机和 ISP 进行通信时所使用的数据链路层协议。以下是 PPP 帧的示意图:

8. **MAC 地址(Media Access Control 或者 Medium Access Control)**:意译为媒体访问控制,或称为物理地址、硬件地址,用来定义网络设备的位置。在 OSI 模型中,第三层网络层负责 IP 地址,第二层数据链路层则负责 MAC 地址。因此一个主机会有一个 MAC 地址,而每个网络位置会有一个专属于它的 IP 地址 。地址是识别某个系统的重要标识符,“名字指出我们所要寻找的资源,地址指出资源所在的地方,路由告诉我们如何到达该处。”
-
+ 
9. **网桥(bridge)**:一种用于数据链路层实现中继,连接两个或多个局域网的网络互连设备。
-10. **交换机(switch )**:广义的来说,交换机指的是一种通信系统中完成信息交换的设备。这里工作在数据链路层的交换机指的是交换式集线器,其实质是一个多接口的网桥
+10. **交换机(switch)**:广义的来说,交换机指的是一种通信系统中完成信息交换的设备。这里工作在数据链路层的交换机指的是交换式集线器,其实质是一个多接口的网桥
### 3.2. 重要知识点总结
@@ -185,13 +199,13 @@ tag:
### 4.1. 基本术语
1. **虚电路(Virtual Circuit)** : 在两个终端设备的逻辑或物理端口之间,通过建立的双向的透明传输通道。虚电路表示这只是一条逻辑上的连接,分组都沿着这条逻辑连接按照存储转发方式传送,而并不是真正建立了一条物理连接。
-2. **IP(Internet Protocol )** : 网际协议 IP 是 TCP/IP 体系中两个最主要的协议之一,是 TCP/IP 体系结构网际层的核心。配套的有 ARP,RARP,ICMP,IGMP。
+2. **IP(Internet Protocol)**:网际协议 IP 是 TCP/IP 体系中两个最主要的协议之一,是 TCP/IP 体系结构网际层的核心。配套的有 ARP,RARP,ICMP,IGMP。
3. **ARP(Address Resolution Protocol)** : 地址解析协议。地址解析协议 ARP 把 IP 地址解析为硬件地址。
-4. **ICMP(Internet Control Message Protocol )**:网际控制报文协议 (ICMP 允许主机或路由器报告差错情况和提供有关异常情况的报告)。
-5. **子网掩码(subnet mask )**:它是一种用来指明一个 IP 地址的哪些位标识的是主机所在的子网以及哪些位标识的是主机的位掩码。子网掩码不能单独存在,它必须结合 IP 地址一起使用。
-6. **CIDR( Classless Inter-Domain Routing )**:无分类域间路由选择 (特点是消除了传统的 A 类、B 类和 C 类地址以及划分子网的概念,并使用各种长度的“网络前缀”(network-prefix)来代替分类地址中的网络号和子网号)。
+4. **ICMP(Internet Control Message Protocol)**:网际控制报文协议(ICMP 允许主机或路由器报告差错情况和提供有关异常情况的报告)。
+5. **子网掩码(subnet mask)**:它是一种用来指明一个 IP 地址的哪些位标识的是主机所在的子网以及哪些位标识的是主机的位掩码。子网掩码不能单独存在,它必须结合 IP 地址一起使用。
+6. **CIDR(Classless Inter-Domain Routing)**:无分类域间路由选择(特点是消除了传统的 A 类、B 类和 C 类地址以及划分子网的概念,并使用各种长度的“网络前缀”(network-prefix)来代替分类地址中的网络号和子网号)。
7. **默认路由(default route)**:当在路由表中查不到能到达目的地址的路由时,路由器选择的路由。默认路由还可以减小路由表所占用的空间和搜索路由表所用的时间。
-8. **路由选择算法(Virtual Circuit)**:路由选择协议的核心部分。因特网采用自适应的,分层次的路由选择协议。
+8. **路由选择算法(Routing Algorithm)**:路由选择协议的核心部分。因特网采用自适应的、分层次的路由选择协议。
### 4.2. 重要知识点总结
@@ -218,11 +232,11 @@ tag:
4. **TCP(Transmission Control Protocol)**:传输控制协议。
5. **UDP(User Datagram Protocol)**:用户数据报协议。
-
+ 
6. **端口(port)**:端口的目的是为了确认对方机器的哪个进程在与自己进行交互,比如 MSN 和 QQ 的端口不同,如果没有端口就可能出现 QQ 进程和 MSN 交互错误。端口又称协议端口号。
7. **停止等待协议(stop-and-wait)**:指发送方每发送完一个分组就停止发送,等待对方确认,在收到确认之后在发送下一个分组。
-8. **流量控制** : 就是让发送方的发送速率不要太快,既要让接收方来得及接收,也不要使网络发生拥塞。
+8. **流量控制**:就是让发送方的发送速率不要太快,既要让接收方来得及接收,也不要使网络发生拥塞。
9. **拥塞控制**:防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。
### 5.2. 重要知识点总结
@@ -267,36 +281,36 @@ tag:
1. **域名系统(DNS)**:域名系统(DNS,Domain Name System)将人类可读的域名 (例如,www.baidu.com) 转换为机器可读的 IP 地址 (例如,220.181.38.148)。我们可以将其理解为专为互联网设计的电话薄。
-
+ 
-https://www.seobility.net/en/wiki/HTTP_headers
+ https://www.seobility.net/en/wiki/HTTP_headers
-2. **文件传输协议(FTP)**:FTP 是 File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于 Internet 上的控制文件的双向传输。同时,它也是一个应用程序(Application)。基于不同的操作系统有不同的 FTP 应用程序,而所有这些应用程序都遵守同一种协议以传输文件。在 FTP 的使用当中,用户经常遇到两个概念:"下载"(Download)和"上传"(Upload)。 "下载"文件就是从远程主机拷贝文件至自己的计算机上;"上传"文件就是将文件从自己的计算机中拷贝至远程主机上。用 Internet 语言来说,用户可通过客户机程序向(从)远程主机上传(下载)文件。
+2. **文件传输协议(FTP)**:FTP 是 File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于 Internet 上的控制文件的双向传输。同时,它也是一个应用程序(Application)。基于不同的操作系统有不同的 FTP 应用程序,而所有这些应用程序都遵守同一种协议以传输文件。在 FTP 的使用当中,用户经常遇到两个概念:“下载”(Download)和“上传”(Upload)。 “下载”文件就是从远程主机拷贝文件至自己的计算机上;“上传”文件就是将文件从自己的计算机中拷贝至远程主机上。用 Internet 语言来说,用户可通过客户机程序向(从)远程主机上传(下载)文件。
-
+ 
3. **简单文件传输协议(TFTP)**:TFTP(Trivial File Transfer Protocol,简单文件传输协议)是 TCP/IP 协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为 69。
4. **远程终端协议(TELNET)**:Telnet 协议是 TCP/IP 协议族中的一员,是 Internet 远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用 telnet 程序,用它连接到服务器。终端使用者可以在 telnet 程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个 telnet 会话,必须输入用户名和密码来登录服务器。Telnet 是常用的远程控制 Web 服务器的方法。
-5. **万维网(WWW)**:WWW 是环球信息网的缩写,(亦作“Web”、“WWW”、“'W3'”,英文全称为“World Wide Web”),中文名字为“万维网”,"环球网"等,常简称为 Web。分为 Web 客户端和 Web 服务器程序。WWW 可以让 Web 客户端(常用浏览器)访问浏览 Web 服务器上的页面。是一个由许多互相链接的超文本组成的系统,通过互联网访问。在这个系统中,每个有用的事物,称为一样“资源”;并且由一个全局“统一资源标识符”(URI)标识;这些资源通过超文本传输协议(Hypertext Transfer Protocol)传送给用户,而后者通过点击链接来获得资源。万维网联盟(英语:World Wide Web Consortium,简称 W3C),又称 W3C 理事会。1994 年 10 月在麻省理工学院(MIT)计算机科学实验室成立。万维网联盟的创建者是万维网的发明者蒂姆·伯纳斯-李。万维网并不等同互联网,万维网只是互联网所能提供的服务其中之一,是靠着互联网运行的一项服务。
+5. **万维网(WWW)**:WWW 是环球信息网的缩写,(亦作“Web”、“WWW”、“'W3'”,英文全称为“World Wide Web”),中文名字为“万维网”,“环球网”等,常简称为 Web。分为 Web 客户端和 Web 服务器程序。WWW 可以让 Web 客户端(常用浏览器)访问浏览 Web 服务器上的页面。是一个由许多互相链接的超文本组成的系统,通过互联网访问。在这个系统中,每个有用的事物,称为一样“资源”;并且由一个全局“统一资源标识符”(URI)标识;这些资源通过超文本传输协议(Hypertext Transfer Protocol)传送给用户,而后者通过点击链接来获得资源。万维网联盟(英语:World Wide Web Consortium,简称 W3C),又称 W3C 理事会。1994 年 10 月在麻省理工学院(MIT)计算机科学实验室成立。万维网联盟的创建者是万维网的发明者蒂姆·伯纳斯-李。万维网并不等同互联网,万维网只是互联网所能提供的服务其中之一,是靠着互联网运行的一项服务。
6. **万维网的大致工作工程:**
-
+ 
7. **统一资源定位符(URL)**:统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
8. **超文本传输协议(HTTP)**:超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的 WWW 文件都必须遵守这个标准。设计 HTTP 最初的目的是为了提供一种发布和接收 HTML 页面的方法。1960 年美国人 Ted Nelson 构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了 HTTP 超文本传输协议标准架构的发展根基。
-HTTP 协议的本质就是一种浏览器与服务器之间约定好的通信格式。HTTP 的原理如下图所示:
+ HTTP 协议的本质就是一种浏览器与服务器之间约定好的通信格式。HTTP 的原理如下图所示:
-
+ 
-10. **代理服务器(Proxy Server)**:代理服务器(Proxy Server)是一种网络实体,它又称为万维网高速缓存。 代理服务器把最近的一些请求和响应暂存在本地磁盘中。当新请求到达时,若代理服务器发现这个请求与暂时存放的的请求相同,就返回暂存的响应,而不需要按 URL 的地址再次去互联网访问该资源。代理服务器可在客户端或服务器工作,也可以在中间系统工作。
-11. **简单邮件传输协议(SMTP)** : SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。 SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。 通过 SMTP 协议所指定的服务器,就可以把 E-mail 寄到收信人的服务器上了,整个过程只要几分钟。SMTP 服务器则是遵循 SMTP 协议的发送邮件服务器,用来发送或中转发出的电子邮件。
+9. **代理服务器(Proxy Server)**:代理服务器(Proxy Server)是一种网络实体,它又称为万维网高速缓存。 代理服务器把最近的一些请求和响应暂存在本地磁盘中。当新请求到达时,若代理服务器发现这个请求与暂时存放的请求相同,就返回暂存的响应,而不需要按 URL 的地址再次去互联网访问该资源。代理服务器可在客户端或服务器工作,也可以在中间系统工作。
+10. **简单邮件传输协议(SMTP)**:SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。 SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。 通过 SMTP 协议所指定的服务器,就可以把 E-mail 寄到收信人的服务器上了,整个过程只要几分钟。SMTP 服务器则是遵循 SMTP 协议的发送邮件服务器,用来发送或中转发出的电子邮件。
-
+ 
-https://www.campaignmonitor.com/resources/knowledge-base/what-is-the-code-that-makes-bcc-or-cc-operate-in-an-email/
+ https://www.campaignmonitor.com/resources/knowledge-base/what-is-the-code-that-makes-bcc-or-cc-operate-in-an-email/
-11. **搜索引擎** :搜索引擎(Search Engine)是指根据一定的策略、运用特定的计算机程序从互联网上搜集信息,在对信息进行组织和处理后,为用户提供检索服务,将用户检索相关的信息展示给用户的系统。搜索引擎包括全文索引、目录索引、元搜索引擎、垂直搜索引擎、集合式搜索引擎、门户搜索引擎与免费链接列表等。
+11. **搜索引擎**:搜索引擎(Search Engine)是指根据一定的策略、运用特定的计算机程序从互联网上搜集信息,在对信息进行组织和处理后,为用户提供检索服务,将用户检索相关的信息展示给用户的系统。搜索引擎包括全文索引、目录索引、元搜索引擎、垂直搜索引擎、集合式搜索引擎、门户搜索引擎与免费链接列表等。
12. **垂直搜索引擎**:垂直搜索引擎是针对某一个行业的专业搜索引擎,是搜索引擎的细分和延伸,是对网页库中的某类专门的信息进行一次整合,定向分字段抽取出需要的数据进行处理后再以某种形式返回给用户。垂直搜索是相对通用搜索引擎的信息量大、查询不准确、深度不够等提出来的新的搜索引擎服务模式,通过针对某一特定领域、某一特定人群或某一特定需求提供的有一定价值的信息和相关服务。其特点就是“专、精、深”,且具有行业色彩,相比较通用搜索引擎的海量信息无序化,垂直搜索引擎则显得更加专注、具体和深入。
13. **全文索引** :全文索引技术是目前搜索引擎的关键技术。试想在 1M 大小的文件中搜索一个词,可能需要几秒,在 100M 的文件中可能需要几十秒,如果在更大的文件中搜索那么就需要更大的系统开销,这样的开销是不现实的。所以在这样的矛盾下出现了全文索引技术,有时候有人叫倒排文档技术。
diff --git a/docs/cs-basics/network/dns.md b/docs/cs-basics/network/dns.md
index 3d3ef0e2254..1f60f52e1e9 100644
--- a/docs/cs-basics/network/dns.md
+++ b/docs/cs-basics/network/dns.md
@@ -1,30 +1,56 @@
---
title: DNS 域名系统详解(应用层)
+description: 详解 DNS 的层次结构与解析流程,覆盖递归/迭代、缓存与权威服务器,明确应用层端口与性能优化要点。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: DNS,域名解析,递归查询,迭代查询,缓存,权威DNS,端口53,UDP
---
-DNS(Domain Name System)域名管理系统,是当用户使用浏览器访问网址之后,使用的第一个重要协议。DNS 要解决的是**域名和 IP 地址的映射问题**。
+在浏览器地址栏输入域名之后,真正发起 HTTP 请求之前,通常要先经过 DNS 解析。
+
+DNS 要解决的是**域名和 IP 地址的映射问题**。它看起来只是“把域名翻译成 IP”,但背后涉及本地缓存、递归查询、迭代查询、权威服务器、根服务器、UDP/TCP 切换等一整套机制。
+
+这篇文章主要回答几个问题:
+
+1. DNS 为什么需要分层设计?
+2. 一次完整的域名解析通常会经过哪些步骤?
+3. 递归查询和迭代查询有什么区别?
+4. DNS 为什么通常基于 UDP,什么情况下会改用 TCP?

-在实际使用中,有一种情况下,浏览器是可以不必动用 DNS 就可以获知域名和 IP 地址的映射的。浏览器在本地会维护一个`hosts`列表,一般来说浏览器要先查看要访问的域名是否在`hosts`列表中,如果有的话,直接提取对应的 IP 地址记录,就好了。如果本地`hosts`列表内没有域名-IP 对应记录的话,那么 DNS 就闪亮登场了。
+在实际使用中,有一种情况下,浏览器是可以不必动用 DNS 就可以获知域名和 IP 地址的映射的。浏览器在本地会维护一个 `hosts` 列表,一般来说浏览器要先查看要访问的域名是否在 `hosts` 列表中,如果有的话,直接提取对应的 IP 地址记录,就好了。如果本地 `hosts` 列表内没有域名-IP 对应记录的话,那么 DNS 就闪亮登场了。
-目前 DNS 的设计采用的是分布式、层次数据库结构,**DNS 是应用层协议,基于 UDP 协议之上,端口为 53** 。
+目前 DNS 的设计采用的是分布式、层次数据库结构,**DNS 是应用层协议,通常基于 UDP 协议,端口为 53**。当响应数据超过 UDP 报文长度限制(512 字节,EDNS0 可扩展至更大)或进行区域传送(Zone Transfer)时,会改用 TCP 协议以保证数据完整性。

## DNS 服务器
-DNS 服务器自底向上可以依次分为以下几个层级(所有 DNS 服务器都属于以下四个类别之一):
+DNS 服务器自底向上可以依次分为以下几个层级(所有 DNS 服务器都属于以下四个类别之一):
- 根 DNS 服务器。根 DNS 服务器提供 TLD 服务器的 IP 地址。目前世界上只有 13 组根服务器,我国境内目前仍没有根服务器。
-- 顶级域 DNS 服务器(TLD 服务器)。顶级域是指域名的后缀,如`com`、`org`、`net`和`edu`等。国家也有自己的顶级域,如`uk`、`fr`和`ca`。TLD 服务器提供了权威 DNS 服务器的 IP 地址。
+- 顶级域 DNS 服务器(TLD 服务器)。顶级域是指域名的后缀,如 `com`、`org`、`net` 和 `edu` 等。国家也有自己的顶级域,如 `uk`、`fr` 和 `ca`。TLD 服务器提供了权威 DNS 服务器的 IP 地址。
- 权威 DNS 服务器。在因特网上具有公共可访问主机的每个组织机构必须提供公共可访问的 DNS 记录,这些记录将这些主机的名字映射为 IP 地址。
- 本地 DNS 服务器。每个 ISP(互联网服务提供商)都有一个自己的本地 DNS 服务器。当主机发出 DNS 请求时,该请求被发往本地 DNS 服务器,它起着代理的作用,并将该请求转发到 DNS 层次结构中。严格说来,不属于 DNS 层级结构。
-世界上并不是只有 13 台根服务器,这是很多人普遍的误解,网上很多文章也是这么写的。实际上,现在根服务器数量远远超过这个数量。最初确实是为 DNS 根服务器分配了 13 个 IP 地址,每个 IP 地址对应一个不同的根 DNS 服务器。然而,由于互联网的快速发展和增长,这个原始的架构变得不太适应当前的需求。为了提高 DNS 的可靠性、安全性和性能,目前这 13 个 IP 地址中的每一个都有多个服务器,截止到 2023 年底,所有根服务器之和达到了 600 多台,未来还会继续增加。
+**世界上真的只有 13 台根服务器吗?** 这是一个流传已久的技术误解。如果你在网上搜索,仍能看到许多陈旧文章宣称“全球仅有 13 台根服务器,且全部由美国控制”。
+
+**事实并非如此。**
+
+最初在设计 DNS(域名系统)架构时,受限于早期 IPv4 数据包的大小限制(UDP 报文需控制在 512 字节以内),预留给根服务器地址的空间确实只够容纳 13 个 IP 地址,每个 IP 地址对应一个不同的根 DNS 服务器。这 13 个地址分别被命名为 `a.root-servers.net` 到 `m.root-servers.net`。
+
+虽然**逻辑上**只有 13 个 IP 地址,但随着互联网规模的爆发,物理上的“单一服务器”早已无法承载全球的查询压力。为了提升 DNS 的可靠性、安全性和响应速度,技术人员引入了 **IP 任播(Anycast)** 技术。
+
+通过任播技术,每一个逻辑 IP 地址背后都可以对应成百上千台分布在全球各地的物理服务器。当你发起查询请求时,互联网路由协议(BGP)会自动将请求引导至地理位置或网络路径上离你**最近**的那台物理实例。
+
+截止到 2023 年底,全球根服务器物理实例总数已超过 1700 台。根据 **[Root-Servers.org](https://root-servers.org/)** 的最新实时监测数据,到 **2026 年,全球根服务器物理实例已突破 1900+ 台**,并正向 2000 台大关迈进。
+
+
## DNS 工作流程
@@ -37,15 +63,15 @@ DNS 服务器自底向上可以依次分为以下几个层级(所有 DNS 服务

-现在,主机`cis.poly.edu`想知道`gaia.cs.umass.edu`的 IP 地址。假设主机`cis.poly.edu`的本地 DNS 服务器为`dns.poly.edu`,并且`gaia.cs.umass.edu`的权威 DNS 服务器为`dns.cs.umass.edu`。
+现在,主机 `cis.poly.edu` 想知道 `gaia.cs.umass.edu` 的 IP 地址。假设主机 `cis.poly.edu` 的本地 DNS 服务器为 `dns.poly.edu`,并且 `gaia.cs.umass.edu` 的权威 DNS 服务器为 `dns.cs.umass.edu`。
-1. 首先,主机`cis.poly.edu`向本地 DNS 服务器`dns.poly.edu`发送一个 DNS 请求,该查询报文包含被转换的域名`gaia.cs.umass.edu`。
-2. 本地 DNS 服务器`dns.poly.edu`检查本机缓存,发现并无记录,也不知道`gaia.cs.umass.edu`的 IP 地址该在何处,不得不向根服务器发送请求。
-3. 根服务器注意到请求报文中含有`edu`顶级域,因此告诉本地 DNS,你可以向`edu`的 TLD DNS 发送请求,因为目标域名的 IP 地址很可能在那里。
-4. 本地 DNS 获取到了`edu`的 TLD DNS 服务器地址,向其发送请求,询问`gaia.cs.umass.edu`的 IP 地址。
-5. `edu`的 TLD DNS 服务器仍不清楚请求域名的 IP 地址,但是它注意到该域名有`umass.edu`前缀,因此返回告知本地 DNS,`umass.edu`的权威服务器可能记录了目标域名的 IP 地址。
-6. 这一次,本地 DNS 将请求发送给权威 DNS 服务器`dns.cs.umass.edu`。
-7. 终于,由于`gaia.cs.umass.edu`向权威 DNS 服务器备案过,在这里有它的 IP 地址记录,权威 DNS 成功地将 IP 地址返回给本地 DNS。
+1. 首先,主机 `cis.poly.edu` 向本地 DNS 服务器 `dns.poly.edu` 发送一个 DNS 请求,该查询报文包含被转换的域名 `gaia.cs.umass.edu`。
+2. 本地 DNS 服务器 `dns.poly.edu` 检查本机缓存,发现并无记录,也不知道 `gaia.cs.umass.edu` 的 IP 地址该在何处,不得不向根服务器发送请求。
+3. 根服务器注意到请求报文中含有 `edu` 顶级域,因此告诉本地 DNS,你可以向 `edu` 的 TLD DNS 发送请求,因为目标域名的 IP 地址很可能在那里。
+4. 本地 DNS 获取到了 `edu` 的 TLD DNS 服务器地址,向其发送请求,询问 `gaia.cs.umass.edu` 的 IP 地址。
+5. `edu` 的 TLD DNS 服务器仍不清楚请求域名的 IP 地址,但是它注意到该域名有 `umass.edu` 前缀,因此返回告知本地 DNS,`umass.edu` 的权威服务器可能记录了目标域名的 IP 地址。
+6. 这一次,本地 DNS 将请求发送给权威 DNS 服务器 `dns.cs.umass.edu`。
+7. 终于,由于 `gaia.cs.umass.edu` 向权威 DNS 服务器备案过,在这里有它的 IP 地址记录,权威 DNS 成功地将 IP 地址返回给本地 DNS。
8. 最后,本地 DNS 获取到了目标域名的 IP 地址,将其返回给请求主机。
除了迭代式查询,还有一种递归式查询如下图,具体过程和上述类似,只是顺序有所不同。
@@ -63,7 +89,7 @@ DNS 的报文格式如下图所示:
DNS 报文分为查询和回答报文,两种形式的报文结构相同。
- 标识符。16 比特,用于标识该查询。这个标识符会被复制到对查询的回答报文中,以便让客户用它来匹配发送的请求和接收到的回答。
-- 标志。1 比特的”查询/回答“标识位,`0`表示查询报文,`1`表示回答报文;1 比特的”权威的“标志位(当某 DNS 服务器是所请求名字的权威 DNS 服务器时,且是回答报文,使用”权威的“标志);1 比特的”希望递归“标志位,显式地要求执行递归查询;1 比特的”递归可用“标志位,用于回答报文中,表示 DNS 服务器支持递归查询。
+- 标志。1 比特的“查询/回答”标识位,`0` 表示查询报文,`1` 表示回答报文;1 比特的“权威的”标志位(当某 DNS 服务器是所请求名字的权威 DNS 服务器时,且是回答报文,使用“权威的”标志);1 比特的“希望递归”标志位,显式地要求执行递归查询;1 比特的“递归可用”标志位,用于回答报文中,表示 DNS 服务器支持递归查询。
- 问题数、回答 RR 数、权威 RR 数、附加 RR 数。分别指示了后面 4 类数据区域出现的数量。
- 问题区域。包含正在被查询的主机名字,以及正被询问的问题类型。
- 回答区域。包含了对最初请求的名字的资源记录。**在回答报文的回答区域中可以包含多条 RR,因此一个主机名能够有多个 IP 地址。**
@@ -72,23 +98,23 @@ DNS 报文分为查询和回答报文,两种形式的报文结构相同。
## DNS 记录
-DNS 服务器在响应查询时,需要查询自己的数据库,数据库中的条目被称为 **资源记录(Resource Record,RR)** 。RR 提供了主机名到 IP 地址的映射。RR 是一个包含了`Name`, `Value`, `Type`, `TTL`四个字段的四元组。
+DNS 服务器在响应查询时,需要查询自己的数据库,数据库中的条目被称为 **资源记录(Resource Record,RR)**。RR 提供了主机名到 IP 地址的映射。RR 是一个包含了 `Name`、`Value`、`Type`、`TTL` 四个字段的四元组。

-`TTL`是该记录的生存时间,它决定了资源记录应当从缓存中删除的时间。
+`TTL` 是该记录的生存时间,它决定了资源记录应当从缓存中删除的时间。
-`Name`和`Value`字段的取值取决于`Type`:
+`Name` 和 `Value` 字段的取值取决于 `Type`:

-- 如果`Type=A`,则`Name`是主机名信息,`Value` 是该主机名对应的 IP 地址。这样的 RR 记录了一条主机名到 IP 地址的映射。
-- 如果 `Type=AAAA` (与 `A` 记录非常相似),唯一的区别是 A 记录使用的是 IPv4,而 `AAAA` 记录使用的是 IPv6。
-- 如果`Type=CNAME` (Canonical Name Record,真实名称记录) ,则`Value`是别名为`Name`的主机对应的规范主机名。`Value`值才是规范主机名。`CNAME` 记录将一个主机名映射到另一个主机名。`CNAME` 记录用于为现有的 `A` 记录创建别名。下文有示例。
-- 如果`Type=NS`,则`Name`是个域,而`Value`是个知道如何获得该域中主机 IP 地址的权威 DNS 服务器的主机名。通常这样的 RR 是由 TLD 服务器发布的。
-- 如果`Type=MX` ,则`Value`是个别名为`Name`的邮件服务器的规范主机名。既然有了 `MX` 记录,那么邮件服务器可以和其他服务器使用相同的别名。为了获得邮件服务器的规范主机名,需要请求 `MX` 记录;为了获得其他服务器的规范主机名,需要请求 `CNAME` 记录。
+- 如果 `Type=A`,则 `Name` 是主机名信息,`Value` 是该主机名对应的 IP 地址。这样的 RR 记录了一条主机名到 IP 地址的映射。
+- 如果 `Type=AAAA`(与 `A` 记录非常相似),唯一的区别是 A 记录使用的是 IPv4,而 `AAAA` 记录使用的是 IPv6。
+- 如果 `Type=CNAME`(Canonical Name Record,真实名称记录),则 `Value` 是别名为 `Name` 的主机对应的规范主机名。`Value` 值才是规范主机名。`CNAME` 记录将一个主机名映射到另一个主机名。`CNAME` 记录用于为现有的 `A` 记录创建别名。下文有示例。
+- 如果 `Type=NS`,则 `Name` 是个域,而 `Value` 是个知道如何获得该域中主机 IP 地址的权威 DNS 服务器的主机名。通常这样的 RR 是由 TLD 服务器发布的。
+- 如果 `Type=MX`,则 `Value` 是个别名为 `Name` 的邮件服务器的规范主机名。既然有了 `MX` 记录,那么邮件服务器可以和其他服务器使用相同的别名。为了获得邮件服务器的规范主机名,需要请求 `MX` 记录;为了获得其他服务器的规范主机名,需要请求 `CNAME` 记录。
-`CNAME`记录总是指向另一则域名,而非 IP 地址。假设有下述 DNS zone:
+`CNAME` 记录总是指向另一则域名,而非 IP 地址。假设有下述 DNS zone:
```plain
NAME TYPE VALUE
diff --git a/docs/cs-basics/network/http-status-codes.md b/docs/cs-basics/network/http-status-codes.md
index e281f44ca19..935c4c7d0b4 100644
--- a/docs/cs-basics/network/http-status-codes.md
+++ b/docs/cs-basics/network/http-status-codes.md
@@ -1,11 +1,25 @@
---
title: HTTP 常见状态码总结(应用层)
+description: 汇总常见 HTTP 状态码含义与使用场景,强调 201/204 等易混淆点,提升接口设计与调试效率。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: HTTP 状态码,2xx,3xx,4xx,5xx,重定向,错误码,201 Created,204 No Content
---
-HTTP 状态码用于描述 HTTP 请求的结果,比如 2xx 就代表请求被成功处理。
+HTTP 状态码是服务端返回给客户端的处理结果摘要。看到一个状态码,基本就能判断请求是成功、重定向、客户端出错,还是服务端出错。
+
+状态码看起来只是数字,但很多码很容易混淆:比如 301 和 302、401 和 403、500 和 502、201 和 204。
+
+这篇文章主要回答几个问题:
+
+1. 1xx、2xx、3xx、4xx、5xx 分别代表什么类型的结果?
+2. 常见成功状态码如 200、201、204 有什么区别?
+3. 常见客户端错误如 400、401、403、404 应该怎么理解?
+4. 常见服务端错误如 500、502、503、504 通常意味着什么?

@@ -15,10 +29,14 @@ HTTP 状态码用于描述 HTTP 请求的结果,比如 2xx 就代表请求被
### 2xx Success(成功状态码)
-- **200 OK**:请求被成功处理。比如我们发送一个查询用户数据的 HTTP 请求到服务端,服务端正确返回了用户数据。这个是我们平时最常见的一个 HTTP 状态码。
-- **201 Created**:请求被成功处理并且在服务端创建了一个新的资源。比如我们通过 POST 请求创建一个新的用户。
-- **202 Accepted**:服务端已经接收到了请求,但是还未处理。
-- **204 No Content**:服务端已经成功处理了请求,但是没有返回任何内容。
+- **200 OK**:请求被成功处理。例如,发送一个查询用户数据的 HTTP 请求到服务端,服务端正确返回了用户数据。这个是我们平时最常见的一个 HTTP 状态码。
+- **201 Created**:请求被成功处理并且在服务端创建了~~一个新的资源~~。例如,通过 POST 请求创建一个新的用户。
+- **202 Accepted**:服务端已经接收到了请求,但是还未处理。例如,发送一个需要服务端花费较长时间处理的请求(如报告生成、Excel 导出),服务端接收了请求但尚未处理完毕。
+- **204 No Content**:服务端已经成功处理了请求,但是没有返回任何内容。例如,发送请求删除一个用户,服务器成功处理了删除操作但没有返回任何内容。
+
+🐛 修正(参见:[issue#2458](https://github.com/Snailclimb/JavaGuide/issues/2458)):201 Created 状态码更准确点来说是创建一个或多个新的资源,可以参考:。
+
+
这里格外提一下 204 状态码,平时学习/工作中见到的次数并不多。
diff --git a/docs/cs-basics/network/http-vs-https.md b/docs/cs-basics/network/http-vs-https.md
index 71c224f1be4..3ab2334610b 100644
--- a/docs/cs-basics/network/http-vs-https.md
+++ b/docs/cs-basics/network/http-vs-https.md
@@ -1,10 +1,26 @@
---
-title: HTTP vs HTTPS(应用层)
+title: HTTP vs HTTPS:区别在哪里、HTTPS 为什么更安全(应用层)
+description: 对比 HTTP 与 HTTPS 的协议与安全机制,解析 SSL/TLS 工作原理与握手流程,明确应用层安全落地细节。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: HTTP,HTTPS,SSL,TLS,加密,认证,端口,安全性,握手流程
---
+HTTP 能传输网页内容,但默认是明文传输。请求和响应如果在网络中被监听、篡改或冒充,HTTP 本身没有足够的保护能力。
+
+HTTPS 不是一个全新的应用层协议,而是在 HTTP 和 TCP 之间加入 TLS/SSL,用加密、身份认证和完整性校验来保护通信过程。
+
+这篇文章主要回答几个问题:
+
+1. HTTP 和 HTTPS 的核心区别是什么?
+2. HTTPS 如何防止窃听、篡改和冒充?
+3. SSL/TLS 握手大致做了哪些事情?
+4. 为什么使用 HTTPS 后,证书、混合内容和性能优化仍然需要关注?
+
## HTTP 协议
### HTTP 协议介绍
@@ -13,9 +29,11 @@ HTTP 协议,全称超文本传输协议(Hypertext Transfer Protocol)。顾
并且,HTTP 是一个无状态(stateless)协议,也就是说服务器不维护任何有关客户端过去所发请求的消息。这其实是一种懒政,有状态协议会更加复杂,需要维护状态(历史信息),而且如果客户或服务器失效,会产生状态的不一致,解决这种不一致的代价更高。
+
+
### HTTP 协议通信过程
-HTTP 是应用层协议,它以 TCP(传输层)作为底层协议,默认端口为 80. 通信过程主要如下:
+HTTP 是应用层协议,它以 TCP(传输层)作为底层协议,默认端口为 80。通信过程主要如下:
1. 服务器在 80 端口等待客户的请求。
2. 浏览器发起到服务器的 TCP 连接(创建套接字 Socket)。
@@ -31,9 +49,9 @@ HTTP 是应用层协议,它以 TCP(传输层)作为底层协议,默认
### HTTPS 协议介绍
-HTTPS 协议(Hyper Text Transfer Protocol Secure),是 HTTP 的加强安全版本。HTTPS 是基于 HTTP 的,也是用 TCP 作为底层协议,并额外使用 SSL/TLS 协议用作加密和安全认证。默认端口号是 443.
+HTTPS 协议(Hyper Text Transfer Protocol Secure),是 HTTP 的加强安全版本。HTTPS 是基于 HTTP 的,也是用 TCP 作为底层协议,并额外使用 SSL/TLS 协议用作加密和安全认证。默认端口号是 443。
-HTTPS 协议中,SSL 通道通常使用基于密钥的加密算法,密钥长度通常是 40 比特或 128 比特。
+HTTPS 中,TLS 握手完成后,通信数据使用对称加密算法(如 AES-128-GCM 或 AES-256-GCM)保护,密钥通过非对称加密(如 RSA-2048/4096 或 ECDH)在握手阶段协商生成。早期 SSL 使用的 40 比特密钥因强度不足已被废弃,现代 TLS 要求对称密钥至少 128 比特。
### HTTPS 协议优点
@@ -41,19 +59,19 @@ HTTPS 协议中,SSL 通道通常使用基于密钥的加密算法,密钥长
## HTTPS 的核心—SSL/TLS 协议
-HTTPS 之所以能达到较高的安全性要求,就是结合了 SSL/TLS 和 TCP 协议,对通信数据进行加密,解决了 HTTP 数据透明的问题。接下来重点介绍一下 SSL/TLS 的工作原理。
+HTTPS 之所以能达到较高的安全性要求,就是结合 SSL/TLS 和 TCP 协议,对通信数据进行加密,解决了 HTTP 数据透明的问题。接下来重点介绍 SSL/TLS 的工作原理。
### SSL 和 TLS 的区别?
**SSL 和 TLS 没有太大的区别。**
-SSL 指安全套接字协议(Secure Sockets Layer),首次发布与 1996 年。SSL 的首次发布其实已经是他的 3.0 版本,SSL 1.0 从未面世,SSL 2.0 则具有较大的缺陷(DROWN 缺陷——Decrypting RSA with Obsolete and Weakened eNcryption)。很快,在 1999 年,SSL 3.0 进一步升级,**新版本被命名为 TLS 1.0**。因此,TLS 是基于 SSL 之上的,但由于习惯叫法,通常把 HTTPS 中的核心加密协议混称为 SSL/TLS。
+SSL 指安全套接层协议(Secure Sockets Layer),首次发布于 1996 年(SSL 3.0)。SSL 1.0 从未面世,SSL 2.0 则具有较大的缺陷(DROWN 缺陷——Decrypting RSA with Obsolete and Weakened eNcryption)。很快,在 1999 年,SSL 3.0 进一步升级,**新版本被命名为 TLS 1.0**。因此,TLS 是基于 SSL 之上的,但由于习惯叫法,通常把 HTTPS 中的核心加密协议混称为 SSL/TLS。目前 SSL 已完全废弃,TLS 1.2 和 TLS 1.3 是现代 HTTPS 的实际标准。
### SSL/TLS 的工作原理
#### 非对称加密
-SSL/TLS 的核心要素是**非对称加密**。非对称加密采用两个密钥——一个公钥,一个私钥。在通信时,私钥仅由解密者保存,公钥由任何一个想与解密者通信的发送者(加密者)所知。可以设想一个场景,
+SSL/TLS 的核心要素是**非对称加密**。非对称加密采用两个密钥:一个公钥,一个私钥。在通信时,私钥仅由解密者保存,公钥由任何一个想与解密者通信的发送者(加密者)所知。可以设想一个场景:
> 在某个自助邮局,每个通信信道都是一个邮箱,每一个邮箱所有者都在旁边立了一个牌子,上面挂着一把钥匙:这是我的公钥,发送者请将信件放入我的邮箱,并用公钥锁好。
>
@@ -83,11 +101,11 @@ SSL/TLS 的核心要素是**非对称加密**。非对称加密采用两个密

-对称加密的密钥生成代价比公私钥对的生成代价低得多,那么有的人会问了,为什么 SSL/TLS 还需要使用非对称加密呢?因为对称加密的保密性完全依赖于密钥的保密性。在双方通信之前,需要商量一个用于对称加密的密钥。我们知道网络通信的信道是不安全的,传输报文对任何人是可见的,密钥的交换肯定不能直接在网络信道中传输。因此,使用非对称加密,对对称加密的密钥进行加密,保护该密钥不在网络信道中被窃听。这样,通信双方只需要一次非对称加密,交换对称加密的密钥,在之后的信息通信中,使用绝对安全的密钥,对信息进行对称加密,即可保证传输消息的保密性。
+对称加密的密钥生成代价比公私钥对的生成代价低得多。那么有的人会问:为什么 SSL/TLS 还需要使用非对称加密呢?因为对称加密的保密性完全依赖于密钥的保密性。在双方通信之前,需要商量一个用于对称加密的密钥。网络通信的信道是不安全的,传输报文对任何人是可见的,密钥的交换肯定不能直接在网络信道中传输。因此,使用非对称加密对对称加密的密钥进行加密,保护该密钥不在网络信道中被窃听。这样,通信双方只需要一次非对称加密,交换对称加密的密钥,在之后的信息通信中,使用绝对安全的密钥对信息进行对称加密,即可保证传输消息的保密性。
#### 公钥传输的信赖性
-SSL/TLS 介绍到这里,了解信息安全的朋友又会想到一个安全隐患,设想一个下面的场景:
+SSL/TLS 介绍到这里,了解信息安全的朋友又会想到一个安全隐患。设想下面的场景:
> 客户端 C 和服务器 S 想要使用 SSL/TLS 通信,由上述 SSL/TLS 通信原理,C 需要先知道 S 的公钥,而 S 公钥的唯一获取途径,就是把 S 公钥在网络信道中传输。要注意网络信道通信中有几个前提:
>
diff --git a/docs/cs-basics/network/http-vs-rpc.md b/docs/cs-basics/network/http-vs-rpc.md
new file mode 100644
index 00000000000..e40fae5779a
--- /dev/null
+++ b/docs/cs-basics/network/http-vs-rpc.md
@@ -0,0 +1,380 @@
+---
+title: 有了 HTTP 协议,为什么还要 RPC?
+category: 计算机基础
+description: HTTP与RPC对比详解,从TCP层出发讲解两种通信方式的本质区别、性能差异(序列化/连接复用)、传输协议对比及在微服务架构中的选型建议。
+keywords:
+ - HTTP
+ - RPC
+ - HTTP vs RPC
+ - 微服务通信
+ - RPC协议
+ - TCP通信
+ - 序列化
+ - RESTful
+ - 服务调用
+---
+
+你好,我是小 G。在我大二下学期那年,看黑马的免费课程,第一次接触到 RPC,当时还是挺懵逼的。
+
+HTTP 接口不是已经能调了吗?
+
+前端调后端是 HTTP,服务端调服务端也可以用 HTTP。写一个 `/user/getById` 接口,传个用户 ID,返回用户信息,这不也能完成远程调用吗?
+
+那为什么还要再搞一个 RPC 增加学习成本呢?这不纯闹嘛!
+
+更容易让人混乱的是,很多文章特别喜欢把 HTTP 和 RPC 放在一起对比,好像它们是同一层的两个协议。看完之后你可能记住了几句话:**HTTP 面向资源,RPC 面向方法;HTTP 对外,RPC 对内;RPC 性能更好。**
+
+这些话不是完全错,但太粗了。
+
+真到项目里,你还是会遇到问题:**用 HTTP 行不行?用 RPC 是不是过度设计?gRPC 明明基于 HTTP/2,为什么又说它是 RPC?**
+
+这篇文章就围绕这个问题聊清楚。
+
+## RPC 不是某一个具体协议
+
+这是一个常见的误区,开始后面的文章之前,非常有必要先提一下。
+
+**HTTP 是协议。而 RPC 不是某一个具体协议,它更像是一种调用方式。**
+
+RPC 全称是 Remote Procedure Call,翻译过来就是远程过程调用。它想解决的问题很朴素:**让你调用远程服务时,尽量像调用本地方法一样。**
+
+
+
+比如本地代码里调用用户服务:
+
+```java
+User user = userService.getUser(1001);
+```
+
+如果 `userService` 就在当前进程里,这只是一次普通方法调用。
+
+但如果用户服务部署在另一台机器上,这件事就复杂了。你要发网络请求,要传方法名和参数,要序列化数据,要处理超时、失败、重试,还要拿到返回结果再反序列化。
+
+RPC 框架想做的事情,就是把这些麻烦尽量封装掉。调用方代码看起来还是:
+
+```java
+User user = userService.getUser(1001);
+```
+
+但底下已经完成了网络通信、序列化、服务寻址和结果返回。
+
+所以更准确的说法不是“HTTP 和 RPC 谁更强”,而是:
+
+**HTTP 是一种应用层协议,RPC 是一种远程调用模型。**
+
+
+
+具体到实现上,RPC 可以有很多种。Dubbo 是 RPC 框架,Thrift 是 RPC 框架,gRPC 也是 RPC 框架。gRPC 官方文档里也说得很直接:客户端可以像调用本地对象一样,调用另一台机器上服务端应用的方法;服务端定义可远程调用的方法以及参数和返回类型。
+
+
+
+这就解释了一个很容易绕晕的点:**gRPC 是 RPC,但它基于 HTTP/2。**
+
+它不是 HTTP 的反面,只是在 HTTP/2 之上提供 RPC 调用。
+
+gRPC 的 GitHub 上专门有一篇文章 [gRPC over HTTP2 基于 HTTP2 的 gRPC 协议](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md) 详细介绍:
+
+
+
+## **光有 TCP 还不够**
+
+要理解 HTTP 和 RPC 的差别,最好先往下看一层。
+
+很多同学知道 HTTP 基于 TCP,RPC 也经常基于 TCP,于是会想:那我直接用 TCP 不就行了吗?
+
+理论上可以,实际很麻烦。
+
+TCP 负责的是可靠传输,它传的是一串连续的字节流。它不关心你的业务消息从哪里开始,到哪里结束。
+
+比如客户端连续发了两次请求:
+
+```text
+getUser:1001
+getOrder:8888
+```
+
+服务端收到的可能不是两段规规整整的消息,而是一段字节流。你必须自己判断:第一条消息在哪里结束,第二条消息从哪里开始。还要考虑半包、粘包、编码、超时、错误码、请求 ID 等问题。
+
+
+
+这就是为什么应用层协议一定要定义消息格式。
+
+HTTP 定义了一套通用格式:请求行、Header、Body、状态码等。MDN 对 HTTP 的定义也很清楚:它是应用层协议,最初用于浏览器和 Web 服务器通信,但也可以用于机器之间通信和 API 访问。
+
+RPC 框架也会定义自己的消息格式。只不过它通常不会围绕 URL 和资源来设计,而是围绕服务、方法、参数和返回值来设计。
+
+说白了,HTTP 和 RPC 都在解决一个问题:
+
+**两个进程隔着网络,怎么把一次业务调用说清楚。**
+
+只是它们的建模方式不一样。
+
+## **HTTP 更像访问资源,RPC 更像调用方法**
+
+HTTP / REST 常见写法是这样的:
+
+```http
+GET /users/1001
+POST /orders
+PUT /orders/888/status
+DELETE /comments/9527
+```
+
+它的心智模型是资源。
+
+`/users/1001` 是一个用户资源,`GET` 表示读取它;`POST /orders` 表示创建订单;`PUT /orders/888/status` 表示修改订单状态。
+
+这种方式很适合对外开放 API。
+
+因为它通用、好理解、好调试。浏览器能访问,Postman 能调,curl 能测,网关也好处理。你给第三方提供接口时,让对方按 HTTP 文档接入,门槛比较低。
+
+RPC 的写法更像这样:
+
+```java
+userService.getUser(1001);
+orderService.createOrder(request);
+inventoryService.deductStock(skuId, count);
+```
+
+它的心智模型是方法调用。
+
+调用方更关心的是:我要调哪个服务?哪个方法?传什么参数?返回什么对象?
+
+
+
+这和 Java 后端平时写代码的习惯更接近。尤其是微服务内部调用时,服务和服务之间本来就是围绕业务方法协作,比如创建订单、扣库存、查询余额、校验权限。RPC 把这种调用关系表达得更直接。
+
+所以 HTTP 和 RPC 最大的区别,不是一个能不能调通,另一个能不能调通。
+
+两者都能调通。
+
+区别在于:**你是把远程交互建模成一次资源访问,还是一次方法调用。**
+
+## **公司内部为什么更常见 RPC?**
+
+HTTP 当然能做内部服务调用。
+
+很多公司内部服务全用 HTTP,也跑得好好的。尤其是服务规模不大、调用链不复杂的时候,HTTP 更简单。
+
+但服务数量上来之后,RPC 的优势会慢慢变明显。
+
+**第一个明显变化是:调用方不想关心对方机器在哪。**
+
+你写业务代码的时候,最好只关心“我要调用用户服务”,而不是关心用户服务有几台机器、IP 是什么、哪台刚下线、哪台权重高。
+
+这就需要服务发现。
+
+Dubbo 官方文档里对服务发现的描述很典型:Provider 把地址注册到注册中心,Consumer 从注册中心读取并订阅地址列表,地址变化时注册中心通知消费者。Dubbo 支持 Nacos、Consul、ZooKeeper 等常见注册中心。
+
+
+
+这类能力当然也可以用 HTTP 做。你可以用注册中心、网关、负载均衡、SDK 自己拼一套。
+
+但 RPC 框架通常会把这些东西直接放进服务调用体系里。
+
+调用方写的是服务接口,底下自动完成服务发现、负载均衡、连接管理、超时控制。业务代码不用到处拼 URL。
+
+**第二个变化是:接口契约会变得更重要。**
+
+HTTP + JSON 很灵活,但灵活也意味着容易松散。
+
+字段名改了,类型改了,枚举值多了一个,调用方可能到运行时才炸。接口文档如果没及时更新,联调时就会很痛苦。
+
+RPC 框架通常会用更强的契约来约束双方。以 gRPC 为例,它常用 Protocol Buffers 作为接口定义语言和消息交换格式。Protocol Buffers 官方文档也说明,它是一种语言无关、平台无关、可扩展的结构化数据序列化机制,可以通过 `.proto` 定义结构并生成不同语言的代码。
+
+这带来的好处是,接口变更更容易被代码生成和编译阶段暴露出来。
+
+当然,契约强不代表不会出事故。
+
+字段怎么兼容,老版本客户端怎么处理,新字段能不能删,枚举能不能改,这些还是要认真设计。只是相比“大家约定一下 JSON 字段”,IDL 会更硬一点。
+
+**第三个变化是:高频内部调用会更在意机器处理效率。**
+
+HTTP + JSON 的好处是可读性强,人类看起来舒服。但机器处理时,它不是最省的方式。字段名、文本格式、解析成本,都会带来额外开销。
+
+RPC 框架常用二进制序列化,比如 Protobuf、Thrift。体积更小,解析也更适合机器处理。
+
+但这里不能说死。
+
+“RPC 一定比 HTTP 快”这句话不严谨。HTTP/2、连接复用、压缩、不同 JSON 库、不同网络环境,都会影响结果。gRPC 自己也基于 HTTP/2,它的优势并不是一句“不是 HTTP”就能解释完。
+
+更稳的说法是:
+
+**在高频服务互调场景里,RPC 框架通常会把序列化、连接复用、超时、重试、负载均衡、链路追踪这些能力做得更贴近内部服务调用。**
+
+这才是它在公司内部常见的原因。
+
+## **RPC 的价值不只是“调用快一点”**
+
+很多人讲 RPC,喜欢把重点放在性能上。
+
+性能当然重要,但我觉得 RPC 更大的价值是服务治理。
+
+一个内部调用真正上线后,不只是发请求、拿响应这么简单。你很快会遇到一堆问题:
+
+- 这个调用超时时间设多少?失败了要不要重试?重试会不会导致重复扣款?
+- 下游服务挂了,上游要不要降级?
+- 哪个接口最近错误率升高了?
+- 一次用户请求经过了几个服务?
+
+这些问题如果全靠业务代码处理,很快就会乱。
+
+RPC 框架通常会和治理能力绑在一起,比如超时控制、负载均衡、服务发现、熔断降级、链路追踪、调用统计等。gRPC 官方介绍里也提到,它支持负载均衡、Tracing、健康检查和认证等可插拔能力。
+
+HTTP 也能做这些。
+
+很多公司会用 API Gateway、服务网格、HTTP SDK、拦截器、链路追踪组件来补齐。做得好也没问题。
+
+所以不要把 RPC 理解成“比 HTTP 高级的东西”。它更像是把内部服务调用里常见的一堆问题,按“远程方法调用”这条路径整理了一遍。
+
+## **那 HTTP 就不适合内部调用吗?**
+
+并不是的哈。如果服务规模不大,团队人数也不多,反而用 HTTP 更省心。
+
+比如一个后台管理系统,拆了几个服务,调用频率也不高。你用 Spring Boot 写几个 REST 接口,配合 OpenAPI 文档、统一错误码、网关鉴权、日志追踪,完全够用。
+
+强上 RPC 可能还会带来额外成本,没意义。
+
+你要引入注册中心,要维护 IDL,要处理代码生成,要培训团队,还要解决本地调试和网关转发问题。服务没几个,调用链也不复杂的时候,这些成本不一定值得。
+
+HTTP 适合这些场景:
+
+- 对外开放 API,比如 Web、App、第三方合作方接入;
+- 团队更看重通用性和调试方便;
+- 服务调用频率不高;
+- 没有成熟 RPC 基础设施;
+- 已经有统一 HTTP 网关、SDK、限流、鉴权和监控体系。
+
+这里有个很简单的判断,分享给大家:
+
+**如果你的系统用 HTTP 已经稳定跑着,也没有明显的调用治理痛点,就没必要为了“微服务味更浓”换 RPC。**
+
+技术选型不是贴标签。
+
+能稳定解决问题更重要。
+
+## **gRPC 为什么容易把人绕晕?**
+
+gRPC 经常让人混乱,就是因为它同时踩在两个概念上。
+
+**一方面,它是 RPC 框架。**
+
+你定义服务和方法,生成客户端和服务端代码,然后像调用方法一样调用远程服务。
+
+**另一方面,它基于 HTTP/2 传输。**
+
+
+
+所以你不能把它简单理解成“HTTP 的对立面”。
+
+更准确地说: **gRPC 用 HTTP/2 做传输,默认使用 Protobuf 作为 IDL 和消息序列化格式,再用 RPC 模型组织调用。**
+
+这里要注意,Protobuf 是 gRPC 最常见的默认搭配,但不是 gRPC 的定义本身。gRPC 协议层允许 `application/grpc+proto`、`application/grpc+json` 或自定义编码。
+
+还有一点经常被忽略:正常 gRPC 响应里,HTTP 层通常是 `:status: 200`,真正的调用结果放在 HTTP/2 Trailers 里的 `grpc-status`、`grpc-message`。
+
+这会带来一个很实际的排查差异。
+
+看 HTTP 接口时,我们习惯先看 HTTP 状态码。`200` 基本代表请求成功,`404` 代表资源不存在,`500` 代表服务端异常。
+
+但看 gRPC 时,不能只看 HTTP 状态码。HTTP 是 200,不代表这次 RPC 业务调用一定成功,还要继续看 `grpc-status`。
+
+这也带来一个工程问题:网关、负载均衡、代理、Service Mesh 是否正确支持 HTTP/2 Trailers,会直接影响 gRPC 调用。如果链路里有组件处理不好 Trailers,问题会很隐蔽。
+
+所以,gRPC 不是“HTTP/2 + Protobuf”这么简单。
+
+HTTP 这一层,它跑在 HTTP/2 上。
+
+编码上,默认搭配 Protobuf,但协议允许其他编码。
+
+调用体验上,它让你像调本地方法一样调远程服务。
+
+状态返回上,它又用了 HTTP/2 Trailers 承载 RPC 调用结果。
+
+这些东西叠在一起,才是它容易把人绕晕的原因。
+
+## **真实选型时,别问哪个更高级**
+
+我更建议你按调用关系选:
+
+- 如果是浏览器、移动端、第三方系统调用,优先 HTTP。原因很简单:通用,接入成本低,调试工具多。对外接口最怕别人接不动。HTTP 在这方面优势太明显了。
+- 如果是公司内部微服务高频互调,可以考虑 RPC。尤其是服务数量多、接口数量多、调用链复杂,对超时、重试、注册发现、链路追踪、负载均衡要求都比较高的时候,RPC 框架会省掉很多重复工作。
+- 如果团队已经有成熟 HTTP 基础设施,也没必要强上 RPC。比如统一网关、服务发现、SDK、链路追踪、限流熔断都有了,大家也习惯用 HTTP,那继续用 HTTP 没问题。
+
+如果要用 gRPC,要提前想清楚几个问题:
+
+- 浏览器不能像后端服务一样直接使用标准 gRPC,通常需要 gRPC-Web 或代理层;
+- 网关和负载均衡是否支持;本地调试是不是方便;
+- 团队是否接受 `.proto` 和代码生成;
+- 线上排查时二进制消息是否会增加理解成本。
+
+gRPC 很强,但不是零成本。
+
+这点要提前说清楚。
+
+## 几个常见误解
+
+### HTTP 和 RPC 谁性能更好?
+
+不能一刀切。
+
+如果拿 HTTP/1.1 + JSON 去和基于 HTTP/2 + Protobuf 的 gRPC 比,在高频内部调用场景里,后者通常更省。
+
+但换个实现,结果就可能不一样。
+
+消息大小、序列化方式、连接复用、压缩、框架实现、网络环境都会影响结果。真正要比,应该拿你自己的接口、数据量和部署环境压测,而不是背一句“RPC 更快”。
+
+### RPC 是不是只能走 TCP?
+
+不是。
+
+RPC 是调用模型,不是传输协议。它可以基于 TCP,也可以基于 HTTP/2。gRPC 就是一个很典型的例子。
+
+### REST 和 RPC 是不是互斥?
+
+不完全互斥。
+
+REST 更偏资源建模,RPC 更偏方法调用。实际项目里经常混用:外部接口走 REST,内部服务走 RPC。这很正常。
+
+### 有了 HTTP/2,还需要 RPC 吗?
+
+HTTP/2 在 HTTP 这一层引入了帧、流、多路复用、头部压缩等能力,提高了同一条 TCP 连接上的并发利用率。
+
+但它不会自动帮你定义服务接口,不会自动生成客户端代码,也不会自动解决服务发现、超时重试、调用治理和版本契约。
+
+还有一个很容易被忽略的差异:调用模式。
+
+普通 HTTP API 大多是一问一答。gRPC 除了最常见的 Unary 调用,还原生支持服务端流、客户端流和双向流。gRPC 官方文档也明确列出了 Unary、Server streaming、Client streaming、Bidirectional streaming 这四种调用模式。
+
+比如日志订阅、长任务进度推送、批量上传、实时同步这类场景,用 streaming 会更自然。你当然也可以用 SSE、WebSocket,或者自己基于 HTTP/2 封装,但那就相当于又在补 RPC 框架已经做好的那部分能力。
+
+所以 HTTP/2 很重要,但它不是 RPC 框架的全部。
+
+### gRPC 是不是等于 HTTP/2 + Protobuf?
+
+不是。
+
+这句话只能用来帮助初学者快速建立印象,不能当严格定义。
+
+更准确的说法是:gRPC 基于 HTTP/2 承载 RPC 调用,默认使用 Protobuf 描述接口和消息,但协议本身允许 JSON 或自定义编码;同时,它还定义了请求路径、Content-Type、Length-Prefixed-Message、Trailers 里的 `grpc-status` 等一整套规则。
+
+所以 gRPC 不是单纯换了一个序列化格式,它是一套 RPC 调用协议和工程约定。
+
+## 最后
+
+HTTP 和 RPC 不是谁取代谁的关系,也不是谁更高级的问题。
+
+HTTP 能调服务,RPC 也能调服务。真正的区别在于,你是想把远程调用当成一次“资源访问”,还是当成一次“方法调用”。
+
+如果是对外接口,比如 Web、App、第三方系统接入,HTTP 通常更合适。它通用、好调试、接入成本低,别人拿 Postman、curl 就能测。
+如果是公司内部服务互调,尤其是服务多、调用链长、接口频繁调用,还要考虑服务发现、超时、重试、负载均衡、链路追踪这些问题,RPC 会更顺手一些。它不是单纯为了快,而是把内部服务调用里的很多麻烦事一起处理掉。
+
+所以,别再简单背“HTTP 对外,RPC 对内”了。
+
+这句话可以帮助入门,但真做项目时,还得看你的调用对象、团队基础设施、排查成本、性能要求和后续维护成本。
+
+系统规模不大,用 HTTP 已经跑得很稳,就别为了“看起来更微服务”强上 RPC。
+
+内部调用越来越复杂,HTTP SDK、网关、监控、重试这些东西越补越多,那就可以认真考虑 RPC。
+
+一句话:**HTTP 没那么弱,RPC 也没那么神。选哪个,主要看它能不能用更低成本解决你现在的问题。**
diff --git a/docs/cs-basics/network/http1.0-vs-http1.1.md b/docs/cs-basics/network/http1.0-vs-http1.1.md
index eab4c324a51..a16a1eae27a 100644
--- a/docs/cs-basics/network/http1.0-vs-http1.1.md
+++ b/docs/cs-basics/network/http1.0-vs-http1.1.md
@@ -1,17 +1,29 @@
---
-title: HTTP 1.0 vs HTTP 1.1(应用层)
+title: HTTP 1.0 vs HTTP 1.1:长连接、缓存、Host 头等核心差异(应用层)
+description: 细致对比 HTTP/1.0 与 HTTP/1.1 的协议差异,涵盖长连接、管道化、缓存与状态码增强等关键变更与实践影响。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: HTTP/1.0,HTTP/1.1,长连接,管道化,缓存,状态码,Host,带宽优化
---
-这篇文章会从下面几个维度来对比 HTTP 1.0 和 HTTP 1.1:
+HTTP/1.0 和 HTTP/1.1 名字只差一个小版本,但它们在连接复用、缓存、Host 头、状态码和带宽优化上都有明显差异。
-- 响应状态码
-- 缓存处理
-- 连接方式
-- Host 头处理
-- 带宽优化
+这些差异不是单纯的协议细节,它们直接影响浏览器如何发请求、服务器如何复用连接、缓存如何生效,以及虚拟主机如何工作。
+
+这篇文章主要回答几个问题:
+
+1. HTTP/1.1 相比 HTTP/1.0 新增了哪些常见状态码?
+2. HTTP/1.0 和 HTTP/1.1 的缓存机制有什么差异?
+3. HTTP/1.1 为什么默认支持长连接?
+4. Host 头和带宽优化分别解决了什么问题?
+
+开始之前,先简单回顾一下 HTTP 协议:
+
+
## 响应状态码
@@ -23,11 +35,11 @@ HTTP/1.0 仅定义了 16 种状态码。HTTP/1.1 中新加入了大量的状态
### HTTP/1.0
-HTTP/1.0 提供的缓存机制非常简单。服务器端使用`Expires`标签来标志(时间)一个响应体,在`Expires`标志时间内的请求,都会获得该响应体缓存。服务器端在初次返回给客户端的响应体中,有一个`Last-Modified`标签,该标签标记了被请求资源在服务器端的最后一次修改。在请求头中,使用`If-Modified-Since`标签,该标签标志一个时间,意为客户端向服务器进行问询:“该时间之后,我要请求的资源是否有被修改过?”通常情况下,请求头中的`If-Modified-Since`的值即为上一次获得该资源时,响应体中的`Last-Modified`的值。
+HTTP/1.0 提供的缓存机制非常简单。服务器端使用 `Expires` 标签来标志(时间)一个响应体,在 `Expires` 标志时间内的请求,都会获得该响应体缓存。服务器端在初次返回给客户端的响应体中,有一个 `Last-Modified` 标签,该标签标记了被请求资源在服务器端的最后一次修改。在请求头中,使用 `If-Modified-Since` 标签,该标签标志一个时间,意为客户端向服务器进行问询:“该时间之后,我要请求的资源是否有被修改过?”通常情况下,请求头中的 `If-Modified-Since` 的值即为上一次获得该资源时,响应体中的 `Last-Modified` 的值。
-如果服务器接收到了请求头,并判断`If-Modified-Since`时间后,资源确实没有修改过,则返回给客户端一个`304 not modified`响应头,表示”缓冲可用,你从浏览器里拿吧!”。
+如果服务器接收到了请求头,并判断`If-Modified-Since`时间后,资源确实没有修改过,则返回给客户端一个 `304 Not Modified` 响应头,表示“缓冲可用,你从浏览器里拿吧!”。
-如果服务器判断`If-Modified-Since`时间后,资源被修改过,则返回给客户端一个`200 OK`的响应体,并附带全新的资源内容,表示”你要的我已经改过的,给你一份新的”。
+如果服务器判断 `If-Modified-Since` 时间后,资源被修改过,则返回给客户端一个 `200 OK` 的响应体,并附带全新的资源内容,表示“你要的我已经改过的,给你一份新的”。

@@ -35,17 +47,17 @@ HTTP/1.0 提供的缓存机制非常简单。服务器端使用`Expires`标签
### HTTP/1.1
-HTTP/1.1 的缓存机制在 HTTP/1.0 的基础上,大大增加了灵活性和扩展性。基本工作原理和 HTTP/1.0 保持不变,而是增加了更多细致的特性。其中,请求头中最常见的特性就是`Cache-Control`,详见 MDN Web 文档 [Cache-Control](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control).
+HTTP/1.1 的缓存机制在 HTTP/1.0 的基础上,大大增加了灵活性和扩展性。基本工作原理和 HTTP/1.0 保持不变,而是增加了更多细致的特性。其中,请求头中最常见的特性就是 `Cache-Control`,详见 MDN Web 文档 [Cache-Control](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control)。
## 连接方式
**HTTP/1.0 默认使用短连接** ,也就是说,客户端和服务器每进行一次 HTTP 操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个 HTML 或其他类型的 Web 页中包含有其他的 Web 资源(如 JavaScript 文件、图像文件、CSS 文件等),每遇到这样一个 Web 资源,浏览器就会重新建立一个 TCP 连接,这样就会导致有大量的“握手报文”和“挥手报文”占用了带宽。
-**为了解决 HTTP/1.0 存在的资源浪费的问题, HTTP/1.1 优化为默认长连接模式 。** 采用长连接模式的请求报文会通知服务端:“我向你请求连接,并且连接成功建立后,请不要关闭”。因此,该 TCP 连接将持续打开,为后续的客户端-服务端的数据交互服务。也就是说在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。
+**为了解决 HTTP/1.0 存在的资源浪费的问题,HTTP/1.1 优化为默认长连接模式。** 采用长连接模式的请求报文会通知服务端:“我向你请求连接,并且连接成功建立后,请不要关闭”。因此,该 TCP 连接将持续打开,为后续的客户端-服务端的数据交互服务。也就是说在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。
-如果 TCP 连接一直保持的话也是对资源的浪费,因此,一些服务器软件(如 Apache)还会支持超时时间的时间。在超时时间之内没有新的请求达到,TCP 连接才会被关闭。
+如果 TCP 连接一直保持的话也是对资源的浪费,因此,一些服务器软件(如 Apache)还会支持超时时间选项。在超时时间之内没有新的请求到达,TCP 连接才会被关闭。
-有必要说明的是,HTTP/1.0 仍提供了长连接选项,即在请求头中加入`Connection: Keep-alive`。同样的,在 HTTP/1.1 中,如果不希望使用长连接选项,也可以在请求头中加入`Connection: close`,这样会通知服务器端:“我不需要长连接,连接成功后即可关闭”。
+有必要说明的是,HTTP/1.0 仍提供了长连接选项,即在请求头中加入 `Connection: Keep-Alive`。同样的,在 HTTP/1.1 中,如果不希望使用长连接选项,也可以在请求头中加入 `Connection: close`,这样会通知服务器端:“我不需要长连接,连接成功后即可关闭”。
**HTTP 协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接。**
@@ -53,9 +65,9 @@ HTTP/1.1 的缓存机制在 HTTP/1.0 的基础上,大大增加了灵活性和
## Host 头处理
-域名系统(DNS)允许多个主机名绑定到同一个 IP 地址上,但是 HTTP/1.0 并没有考虑这个问题,假设我们有一个资源 URL 是 的请求报文中,将会请求的是`GET /home.html HTTP/1.0`.也就是不会加入主机名。这样的报文送到服务器端,服务器是理解不了客户端想请求的真正网址。
+域名系统(DNS)允许多个主机名绑定到同一个 IP 地址上,但是 HTTP/1.0 并没有考虑这个问题。假设我们有一个资源 URL 是 `http://example1.org/home.html`,HTTP/1.0 的请求报文中,将会请求的是 `GET /home.html HTTP/1.0`,也就是不会加入主机名。这样的报文送到服务器端,服务器是理解不了客户端想请求的真正网址。
-因此,HTTP/1.1 在请求头中加入了`Host`字段。加入`Host`字段的报文头部将会是:
+因此,HTTP/1.1 在请求头中加入了 `Host` 字段。加入 `Host` 字段的报文头部将会是:
```plain
GET /home.html HTTP/1.1
@@ -68,21 +80,81 @@ Host: example1.org
### 范围请求
-HTTP/1.1 引入了范围请求(range request)机制,以避免带宽的浪费。当客户端想请求一个文件的一部分,或者需要继续下载一个已经下载了部分但被终止的文件,HTTP/1.1 可以在请求中加入`Range`头部,以请求(并只能请求字节型数据)数据的一部分。服务器端可以忽略`Range`头部,也可以返回若干`Range`响应。
+HTTP/1.1 引入了范围请求(range request)机制,以避免带宽的浪费。当客户端想请求一个文件的一部分,或者需要继续下载一个已经下载了部分但被终止的文件,HTTP/1.1 可以在请求中加入 `Range` 头部,以请求(并只能请求字节型数据)数据的一部分。服务器端可以忽略 `Range` 头部,也可以返回若干 `Range` 响应。
+
+`206 (Partial Content)` 状态码的主要作用是确保客户端和代理服务器能正确识别部分内容响应,避免将其误认为完整资源并错误地缓存。这对于正确处理范围请求和缓存管理非常重要。
+
+一个典型的 HTTP/1.1 范围请求示例:
+
+```http
+# 获取一个文件的前 1024 个字节
+GET /z4d4kWk.jpg HTTP/1.1
+Host: i.imgur.com
+Range: bytes=0-1023
+```
+
+`206 Partial Content` 响应:
+
+```http
+HTTP/1.1 206 Partial Content
+Content-Range: bytes 0-1023/146515
+Content-Length: 1024
+…
+(二进制内容)
+```
+
+简单解释一下 HTTP 范围响应头部中的字段:
+
+- **`Content-Range` 头部**:指示返回数据在整个资源中的位置,包括起始和结束字节以及资源的总长度。例如,`Content-Range: bytes 0-1023/146515` 表示服务器端返回了第 0 到 1023 字节的数据(共 1024 字节),而整个资源的总长度是 146,515 字节。
+- **`Content-Length` 头部**:指示此次响应中实际传输的字节数。例如,`Content-Length: 1024` 表示服务器端传输了 1024 字节的数据。
-如果一个响应包含部分数据的话,那么将带有`206 (Partial Content)`状态码。该状态码的意义在于避免了 HTTP/1.0 代理缓存错误地把该响应认为是一个完整的数据响应,从而把他当作为一个请求的响应缓存。
+`Range` 请求头不仅可以请求单个字节范围,还可以一次性请求多个范围。这种方式被称为“多重范围请求”(multiple range requests)。
-在范围响应中,`Content-Range`头部标志指示出了该数据块的偏移量和数据块的长度。
+客户端想要获取资源的第 0 到 499 字节以及第 1000 到 1499 字节:
+
+```http
+GET /path/to/resource HTTP/1.1
+Host: example.com
+Range: bytes=0-499,1000-1499
+```
+
+服务器端返回多个字节范围,每个范围的内容以分隔符分开:
+
+```http
+HTTP/1.1 206 Partial Content
+Content-Type: multipart/byteranges; boundary=3d6b6a416f9b5
+Content-Length: 376
+
+--3d6b6a416f9b5
+Content-Type: application/octet-stream
+Content-Range: bytes 0-99/2000
+
+(第 0 到 99 字节的数据块)
+
+--3d6b6a416f9b5
+Content-Type: application/octet-stream
+Content-Range: bytes 500-599/2000
+
+(第 500 到 599 字节的数据块)
+
+--3d6b6a416f9b5
+Content-Type: application/octet-stream
+Content-Range: bytes 1000-1099/2000
+
+(第 1000 到 1099 字节的数据块)
+
+--3d6b6a416f9b5--
+```
### 状态码 100
-HTTP/1.1 中新加入了状态码`100`。该状态码的使用场景为,存在某些较大的文件请求,服务器可能不愿意响应这种请求,此时状态码`100`可以作为指示请求是否会被正常响应,过程如下图:
+HTTP/1.1 中新加入了状态码 `100`。该状态码的使用场景为,存在某些较大的文件请求,服务器可能不愿意响应这种请求,此时状态码 `100` 可以作为指示请求是否会被正常响应,过程如下图:


-然而在 HTTP/1.0 中,并没有`100 (Continue)`状态码,要想触发这一机制,可以发送一个`Expect`头部,其中包含一个`100-continue`的值。
+然而在 HTTP/1.0 中,并没有 `100 (Continue)` 状态码,要想触发这一机制,可以发送一个 `Expect` 头部,其中包含一个 `100-continue` 的值。
### 压缩
@@ -90,15 +162,15 @@ HTTP/1.1 中新加入了状态码`100`。该状态码的使用场景为,存在
HTTP/1.1 则对内容编码(content-codings)和传输编码(transfer-codings)做了区分。内容编码总是端到端的,传输编码总是逐跳的。
-HTTP/1.0 包含了`Content-Encoding`头部,对消息进行端到端编码。HTTP/1.1 加入了`Transfer-Encoding`头部,可以对消息进行逐跳传输编码。HTTP/1.1 还加入了`Accept-Encoding`头部,是客户端用来指示他能处理什么样的内容编码。
+HTTP/1.0 包含了 `Content-Encoding` 头部,对消息进行端到端编码。HTTP/1.1 加入了 `Transfer-Encoding` 头部,可以对消息进行逐跳传输编码。HTTP/1.1 还加入了 `Accept-Encoding` 头部,是客户端用来指示它能处理什么样的内容编码。
## 总结
-1. **连接方式** : HTTP 1.0 为短连接,HTTP 1.1 支持长连接。
-1. **状态响应码** : HTTP/1.1 中新加入了大量的状态码,光是错误响应状态码就新增了 24 种。比如说,`100 (Continue)`——在请求大资源前的预热请求,`206 (Partial Content)`——范围请求的标识码,`409 (Conflict)`——请求与当前资源的规定冲突,`410 (Gone)`——资源已被永久转移,而且没有任何已知的转发地址。
-1. **缓存处理** : 在 HTTP1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。
-1. **带宽优化及网络连接的使用** :HTTP1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
-1. **Host 头处理** : HTTP/1.1 在请求头中加入了`Host`字段。
+1. **连接方式**:HTTP/1.0 为短连接,HTTP/1.1 支持长连接。
+2. **状态响应码**:HTTP/1.1 中新加入了大量的状态码,光是错误响应状态码就新增了 24 种。比如说,`100 (Continue)`——在请求大资源前的预热请求,`206 (Partial Content)`——范围请求的标识码,`409 (Conflict)`——请求与当前资源的规定冲突,`410 (Gone)`——资源已被永久转移,而且没有任何已知的转发地址。
+3. **缓存处理**:在 HTTP/1.0 中主要使用 header 里的 `If-Modified-Since`、`Expires` 来作为缓存判断的标准,HTTP/1.1 则引入了更多的缓存控制策略,例如 `Entity Tag`、`If-Unmodified-Since`、`If-Match`、`If-None-Match` 等更多可供选择的缓存头来控制缓存策略。
+4. **带宽优化及网络连接的使用**:HTTP/1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能。HTTP/1.1 则在请求头引入了 `Range` 头域,它允许只请求资源的某个部分,即返回码是 `206 (Partial Content)`,这样就方便了开发者自由选择以便于充分利用带宽和连接。
+5. **Host 头处理**:HTTP/1.1 在请求头中加入了 `Host` 字段。
## 参考资料
diff --git a/docs/cs-basics/network/https-rsa-vs-ecdhe.md b/docs/cs-basics/network/https-rsa-vs-ecdhe.md
new file mode 100644
index 00000000000..8d129b18ac2
--- /dev/null
+++ b/docs/cs-basics/network/https-rsa-vs-ecdhe.md
@@ -0,0 +1,452 @@
+---
+title: HTTPS 握手里的 RSA 和 ECDHE,到底差在哪?(应用层)
+description: 对比 TLS 握手中 RSA 密钥交换与 ECDHE 密钥交换的核心差异,讲清前向安全、密码套件命名、TLS 1.3 变化及面试要点。
+category: 计算机基础
+tag:
+ - 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: HTTPS,RSA,ECDHE,TLS,握手,前向安全,密钥交换,密码套件,TLS 1.3,PreMasterSecret
+---
+
+很多人第一次学 HTTPS,脑子里会留下一个很粗的印象:
+
+**HTTPS = HTTP + 加密,加密 = RSA。 所以,HTTPS = RSA 加密。**
+
+这个理解不是凭空来的。早期很多 HTTPS 部署确实大量使用 RSA 相关的密码套件,很多入门讲解也喜欢拿 RSA 举例。
+
+但严格说,HTTPS 从来不等于 RSA 加密。即使在 TLS 1.0、TLS 1.1 时代,RSA 也只是可选方案之一,协议里还存在 DHE 这类密钥交换方式。到了 TLS 1.3,静态 RSA 密钥交换已经被移除,RSA 更多出现在证书签名、身份认证这类位置。
+
+所以,这篇文章真正要对比的不是“RSA 和 ECDHE 谁更高级”。
+
+**RSA 握手里,会话密钥材料是客户端生成后加密发给服务端;ECDHE 握手里,会话密钥材料不是直接传过去的,而是客户端和服务端各自算出来的。**
+
+这篇文章主要回答几个问题:
+
+1. HTTPS 为什么不等于 RSA 加密?
+2. RSA 握手和 ECDHE 握手的会话密钥材料分别是怎么来的?
+3. ECDHE 为什么能提供前向安全性?
+4. TLS 1.3 为什么移除静态 RSA 密钥交换?
+
+把这些问题讲清楚了,`PreMasterSecret`、`Server Key Exchange`、前向安全、TLS 1.3 为什么移除静态 RSA,后面都能顺着理解。
+
+
+
+## TLS 握手的两个核心问题
+
+HTTPS 仍然基于 HTTP,也仍然依赖 TCP。区别在于,HTTP 报文不会直接裸跑在 TCP 之上,而是先经过 TLS 完成身份认证、密钥协商和加密保护。
+
+握手完成后,真正保护业务数据的通常是 AES-GCM 这类对称加密算法,而不是拿 RSA 去加密完整的请求和响应。
+
+这里有两个问题。
+
+**第一个问题:浏览器和服务器需要协商出一份会话密钥。**
+
+后面传输 HTTP 请求、Cookie、响应体时,就用这份会话密钥做对称加密。对称加密更适合处理大量数据;非对称加密计算成本高,一般不拿来直接加密完整网页内容。
+
+**第二个问题:浏览器需要确认对面真的是目标网站。**
+
+如果只是“服务器发一个公钥给浏览器”,那中间人也可以发自己的公钥。浏览器以为那是目标网站的公钥,后面就把秘密信息加密给了攻击者。证书、CA、数字签名解决的是这件事:证明这个公钥确实和这个域名绑定,而不是路上某个人塞进来的。
+
+RSA 握手和 ECDHE 握手都会面对这两个问题。只是它们解决“会话密钥怎么来”的方式不同。
+
+## RSA 握手:密钥材料加密发送
+
+### 完整握手流程
+
+先看 TLS 1.2 里的 RSA 密钥交换。
+
+浏览器先发 `ClientHello`。这里面会带上客户端支持的 TLS 版本、支持的密码套件、一个随机数 `Client Random`。
+
+服务器收到之后,回 `ServerHello`,选定 TLS 版本和密码套件,也给出一个随机数 `Server Random`,然后把自己的证书发给客户端。
+
+到这里,客户端拿到了服务器证书。它会验证证书链、域名、有效期、签名这些信息。证书验证通过后,客户端就从证书里取出服务器的 RSA 公钥。
+
+接下来是关键步骤:客户端生成一个新的随机值,也就是 `PreMasterSecret`。在 TLS 1.2 的 RSA 密钥交换里,这个值是 **48 字节**。客户端会用服务器证书里的 RSA 公钥加密 `PreMasterSecret`,再把加密结果放进 `Client Key Exchange` 发给服务器。
+
+服务器收到后,用自己的 RSA 私钥解密,拿到同一份 `PreMasterSecret`。
+
+这时,客户端和服务端手里都有三份材料:
+
+```text
+Client Random
+Server Random
+PreMasterSecret
+```
+
+双方再根据这三份材料派生出 `Master Secret`,后续的会话密钥也会从这里继续派生出来。真正传 HTTP 请求和响应时,用的是这些派生出来的对称密钥。
+
+用一句话压缩:
+
+**RSA 握手的会话密钥材料,是客户端生成后“包起来”寄给服务器的。**
+
+这里的“包起来”,靠的就是服务器 RSA 公钥。只有持有对应 RSA 私钥的服务器,才能拆开这个包。
+
+看起来挺合理。客户端生成秘密,服务器私钥解密,双方得到同一份材料,再结合两个随机数派生出后续会话密钥。
+
+但问题也在这里。
+
+### 没有前向安全:长期私钥太值钱
+
+假设攻击者今天抓到了一段 HTTPS 流量,但当时没有服务器私钥,所以看不懂里面的内容。这时他可以先把流量保存下来。
+
+一年后,如果服务器 RSA 私钥泄漏了,会发生什么?
+
+在 RSA 密钥交换里,客户端当年发出的 `PreMasterSecret` 是用服务器 RSA 公钥加密的。如果攻击者完整捕获了握手阶段的明文随机数,也就是 `Client Random`、`Server Random`,同时保存了加密后的 `PreMasterSecret`,再结合后来泄漏的服务器私钥,就可能解开当时的 `PreMasterSecret`,继续派生出那次连接用过的会话密钥。
+
+旧数据就有机会被翻出来。
+
+这里要注意条件:不是“只要私钥泄漏,所有历史流量必然能解”。攻击者至少得拿到足够完整的握手数据和应用数据。如果只有单向片段,或者握手日志不完整,即使有私钥,也未必能把那次会话还原出来。
+
+但从安全设计上看,这个风险已经足够麻烦。长期私钥一旦变成打开历史流量的总钥匙,它的影响就不再只覆盖未来连接,也会波及过去已经发生过的通信。
+
+这里批评的不是 RSA 算法本身“不能用”。RSA 仍然可以用于签名认证,也可以出现在证书体系里。问题出在“用长期不变的服务器私钥去解密历史握手里的密钥材料”。
+
+服务器私钥一旦泄漏,代价太大。
+
+
+
+### 另一个历史包袱:填充预言机攻击
+
+RSA 密钥交换还有一个工程层面的麻烦:`PreMasterSecret` 不是直接裸加密,而是按 RSAES-PKCS1-v1_5 这类格式封装后再加密。
+
+这个细节曾经引出过 Bleichenbacher 这类填充预言机攻击。
+
+它的大致思路是:攻击者不一定要马上拿到服务器私钥,而是反复构造不同的密文发给服务器,观察服务器对“填充错误、版本错误、长度错误”的处理差异。如果服务端在错误码、响应时间、日志行为、连接关闭方式上露出差别,攻击者就可能一点点逼近明文。
+
+这类攻击麻烦的地方在于,它不是单纯的数学问题,而是实现问题。
+
+TLS 1.2 对这类情况做过防御要求:服务端即使解密失败,也不要把具体失败原因暴露出去,而是继续用随机值走完整个流程,避免攻击者通过差异行为判断密文是否接近正确格式。
+
+可规范要求不等于实现可靠。2017 年的 ROBOT 攻击再次说明,一些服务端仍然可能因为细小的行为差异暴露出 RSA 解密 oracle。错误码、耗时、日志、分支路径,只要有一处表现不一致,都可能变成侧信道。
+
+所以,静态 RSA 密钥交换被淘汰,不只是因为它没有前向安全,也因为它把太多风险压到了实现细节上。
+
+### 能否被降级回 RSA?
+
+这里还要补一个容易误解的点。
+
+TLS 1.2 里,客户端会在 `ClientHello` 里带上自己支持的密码套件列表,服务端从里面选一个双方都支持的套件。理论上,如果服务端仍然开放 `TLS_RSA_*` 这类静态 RSA 密钥交换套件,老客户端就可能继续用 RSA 握手。
+
+但这不等于“中间人随便把 ClientHello 里的 ECDHE 删掉,就能让连接悄悄降级到 RSA”。握手最后的 `Finished` 会校验握手 transcript,简单篡改 `ClientHello` 通常会导致校验失败,连接建立不起来。
+
+历史上确实发生过降级相关攻击,比如 FREAK 和 Logjam。它们利用的是当时一些客户端、服务端仍然支持出口级弱密码套件,再结合实现和配置问题,把连接压到更弱的 RSA_EXPORT 或 DHE_EXPORT 路径上,而不是“随便删掉 ECDHE 就能静默成功”。TLS 1.3 在 `ServerHello.random` 里加入降级保护值,也是在提醒我们:协议本身一直在补这类历史攻击面。
+
+真正需要关注的是服务端配置本身:如果已经不需要兼容很老的客户端,就应该关闭静态 RSA 密钥交换套件,只保留支持前向安全的套件。否则,环境里仍然可能存在客户端或错误配置走到 RSA 握手。
+
+这也是排查 TLS 配置时要看密码套件实际协商结果的原因。只看“服务器支持 ECDHE”不够,还要看它是否同时保留了 `TLS_RSA_*` 这类旧套件。
+
+## ECDHE 握手:密钥材料双方协商
+
+### DH 的核心思路
+
+ECDHE 里的 `DHE` 来自 Diffie-Hellman Ephemeral,意思是临时 Diffie-Hellman。前面的 `EC` 是 Elliptic Curve,表示基于椭圆曲线。
+
+别被名字吓住。先不看椭圆曲线,先看 DH 想解决什么问题。
+
+DH 的目标很有意思:通信双方不直接传输共享秘密,却能各自算出同一个共享秘密。
+
+可以粗略理解成这样:
+
+客户端生成一个临时私钥,只留在本地,再算出一个临时公钥发给服务器。服务器也生成一个临时私钥,只留在本地,再算出一个临时公钥发给客户端。
+
+双方交换的都是公钥。攻击者在网络里能看到这些公钥,但看不到双方各自的临时私钥。
+
+接着,客户端用“自己的临时私钥 + 服务器临时公钥”算出共享秘密;服务器用“自己的临时私钥 + 客户端临时公钥”也算出同一个共享秘密。
+
+共享秘密没有在网络上传输过。
+
+ECDHE 只是把这个过程放到椭圆曲线体系里做。椭圆曲线的数学理论更抽象,但在同等安全强度下,它通常能用更短的密钥达到相近的安全级别,运算和传输成本也比传统有限域 DHE 更低。对理解 TLS 握手来说,先记住一句话就够了:
+
+**ECDHE 的会话密钥材料不是某一方生成后发给另一方,而是双方通过临时密钥协商出来的。**
+
+### 完整握手流程
+
+再看 TLS 1.2 里常见的 `ECDHE_RSA` 握手。
+
+客户端还是先发 `ClientHello`,里面有 TLS 版本、支持的密码套件、`Client Random`。服务器回 `ServerHello`,选择一个密码套件,比如:
+
+```text
+TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+```
+
+这个密码套件名要拆开看,不能看到 RSA 就以为它还在用 RSA 加密会话密钥。
+
+- `ECDHE` 表示密钥交换方式。
+- `RSA` 表示认证签名方式。
+- `AES_256_GCM` 表示后续记录数据使用 AES,密钥长度 256 位,模式是 GCM。
+- `SHA384` 指定 TLS 1.2 PRF 和 `Finished` 消息使用的哈希算法。
+
+GCM 本身已经提供记录层的完整性保护,所以这里的 `SHA384` 不再表示记录层 MAC,而是主要参与握手阶段的密钥派生和验证。
+
+服务端接着发证书。以 `ECDHE_RSA` 为例,证书里的 RSA 公钥主要用于验证服务端签名,而不是让客户端拿它加密 `PreMasterSecret`。
+
+然后,ECDHE 和 RSA 握手开始分叉。
+
+在 ECDHE 握手里,服务端会发送 `Server Key Exchange`。这个消息里会包含服务端选择的椭圆曲线参数,以及服务端临时 ECDHE 公钥。
+
+**问题来了:客户端怎么知道这份临时 ECDHE 公钥没有被中间人换掉?**
+
+**答案是签名。**
+
+服务端会用证书对应的私钥,对握手参数做签名。客户端收到后,用证书里的公钥验证签名。如果签名验证通过,客户端就能确认:这份临时 ECDHE 公钥确实来自持有证书私钥的服务器,不是路上被人替换的。
+
+随后客户端也生成自己的临时 ECDHE 私钥和公钥,把客户端临时公钥通过 `Client Key Exchange` 发给服务器。
+
+到这一步,双方都有了计算共享秘密需要的材料。
+
+客户端手里有:
+
+```text
+客户端临时私钥
+服务端临时公钥
+Client Random
+Server Random
+```
+
+服务端手里有:
+
+```text
+服务端临时私钥
+客户端临时公钥
+Client Random
+Server Random
+```
+
+两边各自计算出同一个共享秘密,再派生出后续使用的会话密钥。
+
+这里再强调一次:
+
+**ECDHE_RSA 里的 RSA,不是用来加密传输会话密钥的。它负责证明“这份 ECDHE 临时参数确实是服务器发的”。**
+
+这也是很多人看到密码套件名字后最容易误会的地方。
+
+
+
+### 密码套件名怎么读
+
+TLS 1.2 的密码套件名字通常可以按这条线拆:
+
+```text
+TLS_密钥交换算法_认证算法_WITH_对称加密算法_哈希算法
+```
+
+例如:
+
+```text
+TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+```
+
+可以拆成:
+
+```text
+ECDHE:密钥交换
+RSA:身份认证,也就是服务端签名
+AES_128_GCM:后续记录层加密算法
+SHA256:TLS 1.2 PRF 和 Finished 消息使用的哈希算法;如果是 GCM 套件,它不再充当记录层 MAC
+```
+
+再看另一个:
+
+```text
+TLS_RSA_WITH_AES_128_GCM_SHA256
+```
+
+这里的 `RSA` 出现在 `WITH` 前面,而且没有 `ECDHE`,表示密钥交换和身份认证都和 RSA 绑定。这类就是典型的静态 RSA 密钥交换套件。
+
+到了 TLS 1.3,密码套件命名变了,比如:
+
+```text
+TLS_AES_128_GCM_SHA256
+```
+
+你会发现,它不再把密钥交换和认证方式写进密码套件名里。TLS 1.3 把这些信息拆到其他扩展和握手消息中,密码套件名主要描述记录层 AEAD 算法和 HKDF 使用的哈希算法。
+
+所以,看到 TLS 1.3 的 `TLS_AES_128_GCM_SHA256`,不要误以为它“没有密钥交换”。密钥交换还在,只是不用 TLS 1.2 那套命名方式写出来了。
+
+
+
+## 前向安全与性能代价
+
+### ECDHE 为什么有前向安全
+
+关键在 `E`,也就是 `Ephemeral`,临时。
+
+ECDHE 握手里的私钥不是服务器证书那把长期私钥,而是握手过程中使用的临时私钥。连接结束后,正常情况下不应该再依赖这份临时材料。
+
+这带来的结果是:攻击者今天抓包,未来某天拿到了服务器证书私钥,也不能仅靠这把长期私钥还原过去每次握手里的临时共享秘密。因为当时真正参与密钥协商的是那次握手里的 ECDHE 临时私钥,而不是证书私钥。
+
+证书私钥在这里更像“签字笔”,不是“保险柜钥匙”。
+
+RSA 密钥交换里,服务器私钥可以直接打开客户端发来的 `PreMasterSecret`;ECDHE 里,服务器私钥只是给临时参数签名,证明身份。它不直接参与每次连接共享秘密的计算。
+
+这个角色变化,决定了两者在历史流量保护上的差异。
+
+
+
+不过,前向安全不是免死金牌。
+
+如果服务端随机数质量很差,临时私钥被日志记录下来,或者实现里出现内存泄漏,ECDHE 也救不了你。工程实现里,为了降低握手成本,部分实现还可能短时间复用临时 DH/ECDH 私密材料:有限域 DH 场景常说“指数复用”,ECDH 场景更常说“临时私钥/标量复用”。如果复用时间过长,前向安全的粒度就会变粗。
+
+还有一类风险来自参数校验。比如服务端没有正确校验客户端发来的椭圆曲线点是否在合法曲线上,就可能给无效曲线攻击留下空间。正常开发者不一定会直接写这层代码,但它提醒我们:密码学协议不只是“选对算法”就结束了,TLS 库实现和配置同样重要。
+
+### 会话恢复的影响
+
+还有一个容易被忽略的点:**会话恢复。**
+
+完整 ECDHE 握手要做临时密钥协商,成本不低。为了减少握手开销,TLS 支持会话恢复。客户端下次访问同一个站点时,可以尝试复用之前协商过的会话状态,避免每次都完整走一遍握手。
+
+问题在于,会话恢复也有自己的安全边界。
+
+以 TLS 1.2 的会话票据为例,服务端会用一把票据加密密钥保护会话状态,客户端后续带着票据回来,服务端解开票据后恢复会话。如果这把票据加密密钥长期不轮换,一旦它泄漏,攻击者就可能解开过去收集到的票据,并进一步还原相关恢复会话的密钥材料。
+
+这时,前向安全的窗口就不再是“一次连接”,而会被拉长到“票据加密密钥的生命周期”。
+
+所以线上配置不能只看“是否启用了 ECDHE”。会话票据密钥怎么生成、怎么轮换、是否在多台机器间共享、泄漏后影响多大,也要算进去。
+
+### 性能不是免费的
+
+ECDHE 带来了前向安全,但它也有成本。
+
+RSA 密钥交换的主路径,是服务端用长期 RSA 私钥解开客户端发来的 `PreMasterSecret`。ECDHE_RSA 则需要完成临时 ECDH 协商,还要对服务端临时参数做签名。
+
+对高并发服务来说,TLS 握手会消耗 CPU,尤其是短连接多、会话恢复命中率低的时候。
+
+这里不能简单写成“ECDHE 一定比 RSA 慢”。实际开销取决于 RSA 密钥长度、椭圆曲线选择、签名算法、TLS 库实现、CPU 指令集、会话恢复命中率等因素。比如 X25519、P-256、RSA 2048、RSA 3072 在不同 CPU 和不同 TLS 库上的表现都不一样。
+
+如果真要判断成本,最靠谱的方法不是引用别人的固定数字,而是在目标机器上压测。至少要区分三件事:
+
+```text
+1. 单次密码学操作耗时
+2. 完整 TLS 握手耗时
+3. 业务请求端到端耗时
+```
+
+第一项可以用 `openssl speed` 粗看数量级,比如测试 RSA、ECDH、X25519 的运算能力;第二项要看 TLS 库和服务端配置;第三项还会受网络、连接复用、应用逻辑影响。
+
+所以线上不会只靠“换成 ECDHE”解决所有问题。更常见的做法是配合 TLS 1.3、会话恢复、合理的证书算法和曲线选择,必要时再用硬件加速。
+
+安全性和性能不是二选一,但也不能假装没有成本。
+
+## TLS 1.3 的变化
+
+如果只看 TLS 1.2,RSA 和 ECDHE 可以作为两种密钥交换方式来对比。
+
+但到了 TLS 1.3,静态 RSA 密钥交换已经被移除,握手结构也改了。
+
+TLS 1.2 完整握手通常需要 2 个 RTT。客户端先发 `ClientHello`,服务端回 `ServerHello`、证书和相关握手消息,客户端再发密钥交换和 `Finished`,服务端最后回 `Finished`。
+
+TLS 1.3 则把密钥交换参数提前放进 `ClientHello` 的 `key_share`。服务端第一轮响应就能返回自己的 `key_share`,完整握手通常压到 1 个 RTT。
+
+2 RTT 变 1 RTT 能省多少毫秒,取决于网络环境。同机房可能只是几毫秒;跨地域、移动网络、高丢包场景下,少一个 RTT 才更容易被感知。
+
+不过,TLS 1.3 也不是任何情况下都稳稳 1 RTT。如果客户端带的 `key_share` 和服务端支持的曲线不匹配,服务端会返回 `HelloRetryRequest`,要求客户端换一组参数再来一次。这时握手可能重新接近 2 RTT。
+
+所以生产环境里,客户端和服务端对常见密钥协商组的支持要尽量对齐,比如 `X25519`、`secp256r1` 这类常见选择。否则 TLS 1.3 的 1 RTT 优势可能打折。
+
+
+
+至于后量子混合密钥交换、0-RTT、PSK-only、mTLS,这些都属于另一条线,本文不展开。
+
+## RSA vs ECDHE 核心差异速查
+
+放到一起看,差异就很清楚了。
+
+| 对比项 | RSA 密钥交换 | ECDHE 密钥交换 |
+| ------------------ | ------------------------------------------------------- | ------------------------------------------------------ |
+| 常见版本背景 | TLS 1.2 及更早版本可见 | TLS 1.2 常见,TLS 1.3 延续临时密钥协商方向 |
+| 会话密钥材料怎么来 | 客户端生成 `PreMasterSecret`,用服务器 RSA 公钥加密发送 | 双方各自生成临时密钥对,通过 ECDHE 算出共享秘密 |
+| 服务器私钥的作用 | 解密客户端发来的 `PreMasterSecret` | 对临时 ECDHE 参数签名,证明参数来自真实服务端 |
+| 网络上传了什么 | 加密后的 `PreMasterSecret` | 双方临时公钥和签名后的参数 |
+| 是否支持前向安全 | 不支持 | 支持,前提是临时密钥正确生成、使用后不再保留 |
+| 私钥泄漏后的影响 | 在握手数据完整捕获的情况下,历史流量可能被解密 | 仅靠证书私钥,通常无法解开历史流量 |
+| 典型问题 | 长期私钥价值过高,存在 PKCS#1 v1.5 填充预言机历史包袱 | 握手有额外计算成本,参数校验和临时密钥管理依赖实现质量 |
+| TLS 1.3 情况 | 静态 RSA 密钥交换已移除 | 临时密钥协商成为主线 |
+
+
+
+如果你要在面试里快速讲,可以这样说:
+
+**RSA 握手是“客户端生成秘密,用服务器公钥加密发过去”;ECDHE 握手是“双方交换临时公钥,各自算出同一个秘密”。RSA 的服务器私钥能解历史握手材料,所以没有前向安全;ECDHE 的证书私钥只做签名认证,不直接解会话秘密,所以更适合现代 HTTPS。**
+
+这段就够用了。
+
+### 常见误读:ECDHE_RSA 不是两种算法都加密
+
+再单独说一下 `ECDHE_RSA`,因为这个名字太容易让人误读。
+
+很多人看到:
+
+```text
+TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+```
+
+第一反应是:是不是先做一轮 ECDHE 运算,再做一轮 RSA 加密?
+
+不是。
+
+在这个密码套件里:
+
+密钥交换用 ECDHE;
+身份认证用 RSA 签名;
+后续数据加密用 AES-256-GCM;
+相关哈希使用 SHA384。
+
+这也解释了为什么“HTTPS 还在用 RSA”这句话要小心说。
+
+用 RSA 做证书签名,和用 RSA 做密钥交换,是两件事。
+
+前者在现代 HTTPS 里仍然常见,后者已经不适合作为现代 TLS 的主线。
+
+### RSA 在现代 HTTPS 里的实际角色
+
+学习 HTTPS 握手时,很多入门资料喜欢用一句话概括:
+
+非对称加密交换对称密钥。
+
+这句话在入门阶段有帮助,但不够准确。它更像是在描述早期 RSA 密钥交换的思路。
+
+到了 ECDHE,密钥不是简单“加密后传输”,而是双方协商出来的。到了 TLS 1.3,密钥交换、身份认证、记录层加密的边界更清楚:临时密钥协商负责生成共享秘密,证书负责身份认证,对称加密负责保护后续应用数据。
+
+更准确的说法应该是:
+
+HTTPS 的业务数据通常用对称密钥加密;TLS 握手负责协商这份密钥并验证身份。RSA 可以参与身份认证,也曾经可以参与密钥交换;ECDHE 负责临时密钥协商,能避免历史会话因为未来证书私钥泄漏而直接暴露。
+
+如果把这几件事混在一起,就很容易得出错误结论:看到 RSA 就以为它在加密会话密钥,看到 ECDHE_RSA 就以为两种算法都在做加密。
+
+事实不是这样。
+
+## 用一次完整请求串起来
+
+浏览器访问一个 HTTPS 网站时,TCP 连接先建立起来。接着 TLS 握手开始。
+
+如果是 TLS 1.2 的 RSA 密钥交换,客户端验证证书后,生成 48 字节的 `PreMasterSecret`,用服务器证书里的 RSA 公钥加密发给服务器。服务器用 RSA 私钥解密,双方再结合两个随机数派生会话密钥。
+
+如果是 TLS 1.2 的 ECDHE_RSA,服务器发证书后,还会发 `Server Key Exchange`,里面带着临时 ECDHE 公钥和签名。客户端验证签名后,也生成自己的临时 ECDHE 公钥发回去。双方不传输最终共享秘密,而是各自算出同一个共享秘密,再派生会话密钥。
+
+这两个流程看起来只差了几个握手消息,安全性质却差很多。
+
+RSA 密钥交换的问题是历史包袱太重:长期私钥一旦泄漏,过去保存下来的流量也可能遭殃;再加上 PKCS#1 v1.5 填充预言机这类实现风险,它已经不适合作为现代 TLS 密钥交换方案。
+
+ECDHE 把每次连接的密钥协商换成临时过程,让服务器长期私钥不再成为打开历史流量的钥匙。它也有计算成本,也依赖正确实现和配置,但方向更符合现代 HTTPS 的安全要求。
+
+这篇文章只聚焦一个问题:**RSA 密钥交换和 ECDHE 密钥交换到底差在哪**。如果继续往下讲,还可以展开 TLS 1.3 的 0-RTT、PSK、会话票据轮换、mTLS、证书透明、后量子迁移,这些都值得单独写。
+
+所以,面试里问“RSA 和 ECDHE 握手有什么区别”,不要只回答“一个不支持前向安全,一个支持前向安全”。
+
+真正要讲的是:
+
+**RSA 是把秘密加密送过去;ECDHE 是双方临时协商出来。**
+
+把这句话讲透,后面的 `PreMasterSecret`、`Server Key Exchange`、前向安全、TLS 1.3 为什么移除静态 RSA,就都能顺着讲下去了。
+
+## 面试怎么回答:HTTPS 握手里的 RSA 和 ECDHE,到底差在哪?
+
+RSA 和 ECDHE 的核心区别在于:**会话密钥材料是“传过去的”,还是“协商出来的”**。
+
+在 TLS 1.2 的静态 RSA 握手里,客户端生成 `PreMasterSecret`,用服务器证书里的 RSA 公钥加密后发给服务端,服务端再用 RSA 私钥解密。问题是,如果攻击者保存了当年的握手流量,后来服务器私钥又泄漏,就可能回头解出历史会话密钥,所以它没有前向安全。
+
+ECDHE 不直接传输共享秘密。客户端和服务端各自生成临时密钥对,交换临时公钥后,双方本地算出同一个共享秘密。服务器证书私钥主要用于签名认证,证明临时参数没被中间人替换,而不是用来解密会话密钥。
+
+所以一句话总结:**RSA 是客户端把秘密加密送过去;ECDHE 是双方用临时密钥协商出秘密。ECDHE 支持前向安全,也因此成为现代 HTTPS 的主流方向。**
diff --git a/docs/cs-basics/network/images/arp/2008410143049281.png b/docs/cs-basics/network/images/arp/2008410143049281.png
deleted file mode 100644
index 759fb441f6c..00000000000
Binary files a/docs/cs-basics/network/images/arp/2008410143049281.png and /dev/null differ
diff --git a/docs/cs-basics/network/nat.md b/docs/cs-basics/network/nat.md
index c9c879b4293..657a4e39d5b 100644
--- a/docs/cs-basics/network/nat.md
+++ b/docs/cs-basics/network/nat.md
@@ -1,10 +1,26 @@
---
title: NAT 协议详解(网络层)
+description: 解析 NAT 的地址转换与端口映射机制,结合 LAN/WAN 通信与转换表,理解家庭与企业网络的实践细节。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: NAT,地址转换,端口映射,LAN,WAN,连接跟踪,DHCP
---
+很多设备在家用网络、公司内网里使用的都是私有 IP 地址,比如 `192.168.x.x`、`10.x.x.x`。这些地址不能直接在公网中路由,但内网设备依然可以访问互联网。
+
+这背后通常就有 NAT 在工作。NAT 会在内网地址和公网地址之间做转换,让多个内网设备共享一个或少量公网 IP 对外通信。
+
+这篇文章主要回答几个问题:
+
+1. NAT 主要解决什么问题?
+2. NAT 转换表是如何记录内外网地址和端口映射的?
+3. 内网主机访问公网时,源 IP 和端口会发生什么变化?
+4. NAT 会带来哪些限制,比如外部主动访问内网主机为什么更麻烦?
+
## 应用场景
**NAT 协议(Network Address Translation)** 的应用场景如同它的名称——网络地址转换,应用于内部网到外部网的地址转换过程中。具体地说,在一个小的子网(局域网,Local Area Network,LAN)内,各主机使用的是同一个 LAN 下的 IP 地址,但在该 LAN 以外,在广域网(Wide Area Network,WAN)中,需要一个统一的 IP 地址来标识该 LAN 在整个 Internet 上的位置。
@@ -17,24 +33,24 @@ SOHO 子网的“代理人”,也就是和外界的窗口,通常由路由器

-假设当前场景如上图。中间是一个路由器,它的右侧组织了一个 LAN,网络号为`10.0.0/24`。LAN 侧接口的 IP 地址为`10.0.0.4`,并且该子网内有至少三台主机,分别是`10.0.0.1`,`10.0.0.2`和`10.0.0.3`。路由器的左侧连接的是 WAN,WAN 侧接口的 IP 地址为`138.76.29.7`。
+假设当前场景如上图。中间是一个路由器,它的右侧组织了一个 LAN,网络号为 `10.0.0/24`。LAN 侧接口的 IP 地址为 `10.0.0.4`,并且该子网内有至少三台主机,分别是 `10.0.0.1`、`10.0.0.2` 和 `10.0.0.3`。路由器的左侧连接的是 WAN,WAN 侧接口的 IP 地址为 `138.76.29.7`。
首先,针对以上信息,我们有如下事实需要说明:
-1. 路由器的右侧子网的网络号为`10.0.0/24`,主机号为`10.0.0/8`,三台主机地址,以及路由器的 LAN 侧接口地址,均由 DHCP 协议规定。而且,该 DHCP 运行在路由器内部(路由器自维护一个小 DHCP 服务器),从而为子网内提供 DHCP 服务。
+1. 路由器右侧子网的网络地址为 `10.0.0.0/24`(网络前缀 24 位,主机号占 8 位),三台主机地址以及路由器的 LAN 侧接口地址,均由 DHCP 协议规定。而且,该 DHCP 运行在路由器内部(路由器自维护一个小 DHCP 服务器),从而为子网内提供 DHCP 服务。
2. 路由器的 WAN 侧接口地址同样由 DHCP 协议规定,但该地址是路由器从 ISP(网络服务提供商)处获得,也就是该 DHCP 通常运行在路由器所在区域的 DHCP 服务器上。
现在,路由器内部还运行着 NAT 协议,从而为 LAN-WAN 间通信提供地址转换服务。为此,一个很重要的结构是 **NAT 转换表**。为了说明 NAT 的运行细节,假设有以下请求发生:
-1. 主机`10.0.0.1`向 IP 地址为`128.119.40.186`的 Web 服务器(端口 80)发送了 HTTP 请求(如请求页面)。此时,主机`10.0.0.1`将随机指派一个端口,如`3345`,作为本次请求的源端口号,将该请求发送到路由器中(目的地址将是`128.119.40.186`,但会先到达`10.0.0.4`)。
-2. `10.0.0.4`即路由器的 LAN 接口收到`10.0.0.1`的请求。路由器将为该请求指派一个新的源端口号,如`5001`,并将请求报文发送给 WAN 接口`138.76.29.7`。同时,在 NAT 转换表中记录一条转换记录**138.76.29.7:5001——10.0.0.1:3345**。
-3. 请求报文到达 WAN 接口,继续向目的主机`128.119.40.186`发送。
+1. 主机 `10.0.0.1` 向 IP 地址为 `128.119.40.186` 的 Web 服务器(端口 80)发送了 HTTP 请求(如请求页面)。此时,主机 `10.0.0.1` 将随机指派一个端口,如 `3345`,作为本次请求的源端口号,将该请求发送到路由器中(目的地址将是 `128.119.40.186`,但会先到达 `10.0.0.4`)。
+2. `10.0.0.4` 即路由器的 LAN 接口收到 `10.0.0.1` 的请求。路由器将为该请求指派一个新的源端口号,如 `5001`,并将请求报文发送给 WAN 接口 `138.76.29.7`。同时,在 NAT 转换表中记录一条转换记录 **138.76.29.7:5001——10.0.0.1:3345**。
+3. 请求报文到达 WAN 接口,继续向目的主机 `128.119.40.186` 发送。
之后,将会有如下响应发生:
-1. 主机`128.119.40.186`收到请求,构造响应报文,并将其发送给目的地`138.76.29.7:5001`。
-2. 响应报文到达路由器的 WAN 接口。路由器查询 NAT 转换表,发现`138.76.29.7:5001`在转换表中有记录,从而将其目的地址和目的端口转换成为`10.0.0.1:3345`,再发送到`10.0.0.4`上。
-3. 被转换的响应报文到达路由器的 LAN 接口,继而被转发至目的地`10.0.0.1`。
+1. 主机 `128.119.40.186` 收到请求,构造响应报文,并将其发送给目的地 `138.76.29.7:5001`。
+2. 响应报文到达路由器的 WAN 接口。路由器查询 NAT 转换表,发现 `138.76.29.7:5001` 在转换表中有记录,从而将其目的地址和目的端口转换成为 `10.0.0.1:3345`,再发送到 `10.0.0.4` 上。
+3. 被转换的响应报文到达路由器的 LAN 接口,继而被转发至目的地 `10.0.0.1`。

@@ -45,7 +61,7 @@ SOHO 子网的“代理人”,也就是和外界的窗口,通常由路由器
针对以上过程,有以下几个重点需要强调:
1. 当请求报文到达路由器,并被指定了新端口号时,由于端口号有 16 位,因此,通常来说,一个路由器管理的 LAN 中的最大主机数 $≈65500$($2^{16}$ 的地址空间),但通常 SOHO 子网内不会有如此多的主机数量。
-2. 对于目的服务器来说,从来不知道“到底是哪个主机给我发送的请求”,它只知道是来自`138.76.29.7:5001`的路由器转发的请求。因此,可以说,**路由器在 WAN 和 LAN 之间起到了屏蔽作用,**所有内部主机发送到外部的报文,都具有同一个 IP 地址(不同的端口号),所有外部发送到内部的报文,也都只有一个目的地(不同端口号),是经过了 NAT 转换后,外部报文才得以正确地送达内部主机。
+2. 对于目的服务器来说,从来不知道“到底是哪个主机给我发送的请求”,它只知道是来自 `138.76.29.7:5001` 的路由器转发的请求。因此,可以说,**路由器在 WAN 和 LAN 之间起到了屏蔽作用**,所有内部主机发送到外部的报文,都具有同一个 IP 地址(不同的端口号),所有外部发送到内部的报文,也都只有一个目的地(不同端口号),是经过了 NAT 转换后,外部报文才得以正确地送达内部主机。
3. 在报文穿过路由器,发生 NAT 转换时,如果 LAN 主机 IP 已经在 NAT 转换表中注册过了,则不需要路由器新指派端口,而是直接按照转换记录穿过路由器。同理,外部报文发送至内部时也如此。
总结 NAT 协议的特点,有以下几点:
@@ -55,6 +71,6 @@ SOHO 子网的“代理人”,也就是和外界的窗口,通常由路由器
3. WAN 的 ISP 变更接口地址时,无需通告 LAN 内主机。
4. LAN 主机对 WAN 不可见,不可直接寻址,可以保证一定程度的安全性。
-然而,NAT 协议由于其独特性,存在着一些争议。比如,可能你已经注意到了,NAT 协议在 LAN 以外,标识一个内部主机时,使用的是端口号,因为 IP 地址都是相同的。 这种将端口号作为主机寻址的行为,可能会引发一些误会。此外,路由器作为网络层的设备,修改了传输层的分组内容(修改了源 IP 地址和端口号),同样是不规范的行为。但是,尽管如此,NAT 协议作为 IPv4 时代的产物,极大地方便了一些本来棘手的问题,一直被沿用至今。
+然而,NAT 协议由于其独特性,存在着一些争议。比如,可能你已经注意到了,**NAT 协议在 LAN 以外,标识一个内部主机时,使用的是端口号,因为 IP 地址都是相同的**。这种将端口号作为主机寻址的行为,可能会引发一些误会。此外,路由器作为网络层的设备,修改了传输层的分组内容(修改了源 IP 地址和端口号),同样是不规范的行为。但是,尽管如此,NAT 协议作为 IPv4 时代的产物,极大地方便了一些本来棘手的问题,一直被沿用至今。
diff --git a/docs/cs-basics/network/network-attack-means.md b/docs/cs-basics/network/network-attack-means.md
index 7f142af00c3..0f5546229c6 100644
--- a/docs/cs-basics/network/network-attack-means.md
+++ b/docs/cs-basics/network/network-attack-means.md
@@ -1,13 +1,27 @@
---
-title: 网络攻击常见手段总结
+title: 网络攻击常见手段总结(安全)
+description: 总结常见 TCP/IP 攻击与防护思路,覆盖 DDoS、IP/ARP 欺骗、中间人等手段,强调工程防护实践。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: 网络攻击,DDoS,IP 欺骗,ARP 欺骗,中间人攻击,扫描,防护
---
> 本文整理完善自[TCP/IP 常见攻击手段 - 暖蓝笔记 - 2021](https://mp.weixin.qq.com/s/AZwWrOlLxRSSi-ywBgZ0fA)这篇文章。
-这篇文章的内容主要是介绍 TCP/IP 常见攻击手段,尤其是 DDoS 攻击,也会补充一些其他的常见网络攻击手段。
+TCP/IP 协议栈追求互联互通,但很多机制在设计之初并没有把今天的攻击规模和对抗强度都考虑进去。
+
+IP 欺骗、SYN Flood、DDoS、ARP 欺骗、DNS 劫持这些攻击,表面上各不相同,本质上都在利用网络协议里的信任假设、资源消耗点或解析链路。
+
+这篇文章主要回答几个问题:
+
+1. TCP/IP 常见攻击手段分别利用了什么机制?
+2. IP 欺骗、SYN Flood、DDoS 等攻击大致是怎么发生的?
+3. 常见网络攻击会造成哪些影响?
+4. 面对这些攻击,通常有哪些基础防御思路?
## IP 欺骗
@@ -17,9 +31,9 @@ tag:
### 通过 IP 地址我们能知道什么?
-通过 IP 地址,我们就可以知道判断访问对象服务器的位置,从而将消息发送到服务器。一般发送者发出的消息首先经过子网的集线器,转发到最近的路由器,然后根据路由位置访问下一个路由器的位置,直到终点
+通过 IP 地址,我们就可以判断访问对象服务器的位置,从而将消息发送到服务器。一般发送者发出的消息首先经过子网的集线器,转发到最近的路由器,然后根据路由位置访问下一个路由器的位置,直到终点。
-**IP 头部格式** :
+**IP 头部格式**:

@@ -27,7 +41,7 @@ tag:
骗呗,拐骗,诱骗!
-IP 欺骗技术就是**伪造**某台主机的 IP 地址的技术。通过 IP 地址的伪装使得某台主机能够**伪装**另外的一台主机,而这台主机往往具有某种特权或者被另外的主机所信任。
+IP 欺骗技术就是伪造某台主机的 IP 地址的技术。通过 IP 地址的伪装使得某台主机能够伪装另外的一台主机,而这台主机往往具有某种特权或者被另外的主机所信任。
假设现在有一个合法用户 **(1.1.1.1)** 已经同服务器建立正常的连接,攻击者构造攻击的 TCP 数据,伪装自己的 IP 为 **1.1.1.1**,并向服务器发送一个带有 RST 位的 TCP 数据段。服务器接收到这样的数据后,认为从 **1.1.1.1** 发送的连接有错误,就会清空缓冲区中建立好的连接。
@@ -39,14 +53,14 @@ IP 欺骗技术就是**伪造**某台主机的 IP 地址的技术。通过 IP
虽然无法预防 IP 欺骗,但可以采取措施来阻止伪造数据包渗透网络。**入口过滤** 是防范欺骗的一种极为常见的防御措施,如 BCP38(通用最佳实践文档)所示。入口过滤是一种数据包过滤形式,通常在[网络边缘](https://www.cloudflare.com/learning/serverless/glossary/what-is-edge-computing/)设备上实施,用于检查传入的 IP 数据包并确定其源标头。如果这些数据包的源标头与其来源不匹配或者看上去很可疑,则拒绝这些数据包。一些网络还实施出口过滤,检查退出网络的 IP 数据包,确保这些数据包具有合法源标头,以防止网络内部用户使用 IP 欺骗技术发起出站恶意攻击。
-## SYN Flood(洪水)
+## SYN Flood(洪水)
### SYN Flood 是什么?
-SYN Flood 是互联网上最原始、最经典的 DDoS(Distributed Denial of Service,分布式拒绝服务)攻击之一,旨在耗尽可用服务器资源,致使服务器无法传输合法流量
+SYN Flood 是互联网上最原始、最经典的 DDoS(Distributed Denial of Service,分布式拒绝服务)攻击之一,旨在耗尽可用服务器资源,致使服务器无法传输合法流量。
SYN Flood 利用了 TCP 协议的三次握手机制,攻击者通常利用工具或者控制僵尸主机向服务器发送海量的变源 IP 地址或变源端口的 TCP SYN 报文,服务器响应了这些报文后就会生成大量的半连接,当系统资源被耗尽后,服务器将无法提供正常的服务。
-增加服务器性能,提供更多的连接能力对于 SYN Flood 的海量报文来说杯水车薪,防御 SYN Flood 的关键在于判断哪些连接请求来自于真实源,屏蔽非真实源的请求以保障正常的业务请求能得到服务。
+增加服务器性能、提供更多的连接能力对于 SYN Flood 的海量报文来说杯水车薪。防御 SYN Flood 的关键在于判断哪些连接请求来自于真实源,屏蔽非真实源的请求以保障正常的业务请求能得到服务。

@@ -77,7 +91,7 @@ B 为帮助 A 能顺利连接,需要**分配内核资源**维护半开连接
### SYN Flood 的常见形式有哪些?
-**恶意用户可通过三种不同方式发起 SYN Flood 攻击**:
+恶意用户可通过三种不同方式发起 SYN Flood 攻击:
1. **直接攻击:** 不伪造 IP 地址的 SYN 洪水攻击称为直接攻击。在此类攻击中,攻击者完全不屏蔽其 IP 地址。由于攻击者使用具有真实 IP 地址的单一源设备发起攻击,因此很容易发现并清理攻击者。为使目标机器呈现半开状态,黑客将阻止个人机器对服务器的 SYN-ACK 数据包做出响应。为此,通常采用以下两种方式实现:部署防火墙规则,阻止除 SYN 数据包以外的各类传出数据包;或者,对传入的所有 SYN-ACK 数据包进行过滤,防止其到达恶意用户机器。实际上,这种方法很少使用(即便使用过也不多见),因为此类攻击相当容易缓解 – 只需阻止每个恶意系统的 IP 地址。哪怕攻击者使用僵尸网络(如 [Mirai 僵尸网络](https://www.cloudflare.com/learning/ddos/glossary/mirai-botnet/)),通常也不会刻意屏蔽受感染设备的 IP。
2. **欺骗攻击:** 恶意用户还可以伪造其发送的各个 SYN 数据包的 IP 地址,以便阻止缓解措施并加大身份暴露难度。虽然数据包可能经过伪装,但还是可以通过这些数据包追根溯源。此类检测工作很难开展,但并非不可实现;特别是,如果 Internet 服务提供商 (ISP) 愿意提供帮助,则更容易实现。
@@ -97,7 +111,7 @@ B 为帮助 A 能顺利连接,需要**分配内核资源**维护半开连接
此策略要求服务器创建 Cookie。为避免在填充积压工作时断开连接,服务器使用 SYN-ACK 数据包响应每一项连接请求,而后从积压工作中删除 SYN 请求,同时从内存中删除请求,保证端口保持打开状态并做好重新建立连接的准备。如果连接是合法请求并且已将最后一个 ACK 数据包从客户端机器发回服务器,服务器将重建(存在一些限制)SYN 积压工作队列条目。虽然这项缓解措施势必会丢失一些 TCP 连接信息,但好过因此导致对合法用户发起拒绝服务攻击。
-## UDP Flood(洪水)
+## UDP Flood(洪水)
### UDP Flood 是什么?
@@ -120,11 +134,11 @@ B 为帮助 A 能顺利连接,需要**分配内核资源**维护半开连接

-### 如何缓解 UDP Flooding?
+### 如何缓解 UDP Flood?
大多数操作系统部分限制了 **ICMP** 报文的响应速率,以中断需要 ICMP 响应的 **DDoS** 攻击。这种缓解的一个缺点是在攻击过程中,合法的数据包也可能被过滤。如果 **UDP Flood** 的容量足够高以使目标服务器的防火墙的状态表饱和,则在服务器级别发生的任何缓解都将不足以应对目标设备上游的瓶颈。
-## HTTP Flood(洪水)
+## HTTP Flood(洪水)
### HTTP Flood 是什么?
@@ -149,11 +163,11 @@ HTTP 洪水攻击有两种:
其他阻止 HTTP 洪水攻击的途径包括使用 Web 应用程序防火墙 (WAF)、管理 IP 信誉数据库以跟踪和有选择地阻止恶意流量,以及由工程师进行动态分析。Cloudflare 具有超过 2000 万个互联网设备的规模优势,能够分析来自各种来源的流量并通过快速更新的 WAF 规则和其他防护策略来缓解潜在的攻击,从而消除应用程序层 DDoS 流量。
-## DNS Flood(洪水)
+## DNS Flood(洪水)
### DNS Flood 是什么?
-域名系统(DNS)服务器是互联网的“电话簿“;互联网设备通过这些服务器来查找特定 Web 服务器以便访问互联网内容。DNS Flood 攻击是一种分布式拒绝服务(DDoS)攻击,攻击者用大量流量淹没某个域的 DNS 服务器,以尝试中断该域的 DNS 解析。如果用户无法找到电话簿,就无法查找到用于调用特定资源的地址。通过中断 DNS 解析,DNS Flood 攻击将破坏网站、API 或 Web 应用程序响应合法流量的能力。很难将 DNS Flood 攻击与正常的大流量区分开来,因为这些大规模流量往往来自多个唯一地址,查询该域的真实记录,模仿合法流量。
+域名系统(DNS)服务器是互联网的“电话簿”;互联网设备通过这些服务器来查找特定 Web 服务器以便访问互联网内容。DNS Flood 攻击是一种分布式拒绝服务(DDoS)攻击,攻击者用大量流量淹没某个域的 DNS 服务器,以尝试中断该域的 DNS 解析。如果用户无法找到电话簿,就无法查找到用于调用特定资源的地址。通过中断 DNS 解析,DNS Flood 攻击将破坏网站、API 或 Web 应用程序响应合法流量的能力。很难将 DNS Flood 攻击与正常的大流量区分开来,因为这些大规模流量往往来自多个唯一地址,查询该域的真实记录,模仿合法流量。
### DNS Flood 的攻击原理是什么?
@@ -163,13 +177,13 @@ HTTP 洪水攻击有两种:
DNS Flood 攻击不同于 [DNS 放大攻击](https://www.cloudflare.com/zh-cn/learning/ddos/dns-amplification-ddos-attack/)。与 DNS Flood 攻击不同,DNS 放大攻击反射并放大不安全 DNS 服务器的流量,以便隐藏攻击的源头并提高攻击的有效性。DNS 放大攻击使用连接带宽较小的设备向不安全的 DNS 服务器发送无数请求。这些设备对非常大的 DNS 记录发出小型请求,但在发出请求时,攻击者伪造返回地址为目标受害者。这种放大效果让攻击者能借助有限的攻击资源来破坏较大的目标。
-### 如何防护 DNS Flood?
+### 如何防护 DNS Flood?
DNS Flood 对传统上基于放大的攻击方法做出了改变。借助轻易获得的高带宽僵尸网络,攻击者现能针对大型组织发动攻击。除非被破坏的 IoT 设备得以更新或替换,否则抵御这些攻击的唯一方法是使用一个超大型、高度分布式的 DNS 系统,以便实时监测、吸收和阻止攻击流量。
## TCP 重置攻击
-在 **TCP** 重置攻击中,攻击者通过向通信的一方或双方发送伪造的消息,告诉它们立即断开连接,从而使通信双方连接中断。正常情况下,如果客户端收发现到达的报文段对于相关连接而言是不正确的,**TCP** 就会发送一个重置报文段,从而导致 **TCP** 连接的快速拆卸。
+在 **TCP** 重置攻击中,攻击者通过向通信的一方或双方发送伪造的消息,告诉它们立即断开连接,从而使通信双方连接中断。正常情况下,如果客户端发现到达的报文段对于相关连接而言是不正确的,**TCP** 就会发送一个重置报文段,从而导致 **TCP** 连接的快速拆卸。
**TCP** 重置攻击利用这一机制,通过向通信方发送伪造的重置报文段,欺骗通信双方提前关闭 TCP 连接。如果伪造的重置报文段完全逼真,接收者就会认为它有效,并关闭 **TCP** 连接,防止连接被用来进一步交换信息。服务端可以创建一个新的 **TCP** 连接来恢复通信,但仍然可能会被攻击者重置连接。万幸的是,攻击者需要一定的时间来组装和发送伪造的报文,所以一般情况下这种攻击只对长连接有杀伤力,对于短连接而言,你还没攻击呢,人家已经完成了信息交换。
@@ -184,7 +198,7 @@ DNS Flood 对传统上基于放大的攻击方法做出了改变。借助轻易
- 嗅探通信双方的交换信息。
- 截获一个 `ACK` 标志位置位 1 的报文段,并读取其 `ACK` 号。
- 伪造一个 TCP 重置报文段(`RST` 标志位置为 1),其序列号等于上面截获的报文的 `ACK` 号。这只是理想情况下的方案,假设信息交换的速度不是很快。大多数情况下为了增加成功率,可以连续发送序列号不同的重置报文。
-- 将伪造的重置报文发送给通信的一方或双方,时其中断连接。
+- 将伪造的重置报文发送给通信的一方或双方,使其中断连接。
为了实验简单,我们可以使用本地计算机通过 `localhost` 与自己通信,然后对自己进行 TCP 重置攻击。需要以下几个步骤:
@@ -220,10 +234,10 @@ nc 127.0.0.1 8000
这段代码告诉 `scapy` 在 `lo0` 网络接口上嗅探数据包,并记录所有 TCP 连接的详细信息。
-- **iface** : 告诉 scapy 在 `lo0`(localhost)网络接口上进行监听。
-- **lfilter** : 这是个过滤器,告诉 scapy 忽略所有不属于指定的 TCP 连接(通信双方皆为 `localhost`,且端口号为 `8000`)的数据包。
-- **prn** : scapy 通过这个函数来操作所有符合 `lfilter` 规则的数据包。上面的例子只是将数据包打印到终端,下文将会修改函数来伪造重置报文。
-- **count** : scapy 函数返回之前需要嗅探的数据包数量。
+- **iface**:告诉 scapy 在 `lo0`(localhost)网络接口上进行监听。
+- **lfilter**:这是个过滤器,告诉 scapy 忽略所有不属于指定的 TCP 连接(通信双方皆为 `localhost`,且端口号为 `8000`)的数据包。
+- **prn**:scapy 通过这个函数来操作所有符合 `lfilter` 规则的数据包。上面的例子只是将数据包打印到终端,下文将会修改函数来伪造重置报文。
+- **count**:scapy 函数返回之前需要嗅探的数据包数量。
> 发送伪造的重置报文
@@ -250,7 +264,7 @@ nc 127.0.0.1 8000
### 什么是中间人?
-攻击中间人攻击英文名叫 Man-in-the-MiddleAttack,简称「MITM 攻击」。指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方 直接对话,但事实上整个会话都被攻击者完全控制。我们画一张图:
+中间人攻击英文名叫 Man-in-the-Middle Attack,简称「MITM 攻击」。指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。我们画一张图:

@@ -262,11 +276,11 @@ nc 127.0.0.1 8000
在安全领域有句话:**我们没有办法杜绝网络犯罪,只好想办法提高网络犯罪的成本**。既然没法杜绝这种情况,那我们就想办法提高作案的成本,今天我们就简单了解下基本的网络安全知识,也是面试中的高频面试题了。
-为了避免双方说活不算数的情况,双方引入第三家机构,将合同原文给可信任的第三方机构,只要这个机构不监守自盗,合同就相对安全。
+为了避免双方说话不算数的情况,双方引入第三家机构,将合同原文给可信任的第三方机构,只要这个机构不监守自盗,合同就相对安全。
**如果第三方机构内部不严格或容易出现纰漏?**
-虽然我们将合同原文给第三方机构了,为了防止内部人员的更改,需要采取什么措施呢
+虽然我们将合同原文给第三方机构了,为了防止内部人员的更改,需要采取什么措施呢?
一种可行的办法是引入 **摘要算法** 。即合同和摘要一起,为了简单的理解摘要。大家可以想象这个摘要为一个函数,这个函数对原文进行了加密,会产生一个唯一的散列值,一旦原文发生一点点变化,那么这个散列值将会变化。
@@ -278,15 +292,15 @@ nc 127.0.0.1 8000
**出现内鬼了怎么办?**
-看似很安全的场面了,理论上来说杜绝了篡改合同的做法。主要某个员工同时具有修改合同和摘要的权利,那搞事儿就是时间的问题了,毕竟没哪个系统可以完全的杜绝员工接触敏感信息,除非敏感信息都不存在。所以能不能考虑将合同和摘要分开存储呢
+看似很安全的场面了,理论上来说杜绝了篡改合同的做法。主要某个员工同时具有修改合同和摘要的权利,那搞事儿就是时间的问题了,毕竟没哪个系统可以完全的杜绝员工接触敏感信息,除非敏感信息都不存在。所以能不能考虑将合同和摘要分开存储呢?
**那如何确保员工不会修改合同呢?**
-这确实蛮难的,不过办法总比困难多。我们将合同放在双方手中,摘要放在第三方机构,篡改难度进一步加大
+这确实蛮难的,不过办法总比困难多。我们将合同放在双方手中,摘要放在第三方机构,篡改难度进一步加大。
**那么员工万一和某个用户串通好了呢?**
-看来放在第三方的机构还是不好使,同样存在不小风险。所以还需要寻找新的方案,这就出现了 **数字签名和证书**。
+看来放在第三方的机构还是不好使,同样存在不小风险。所以还需要寻找新的方案,这就出现了**数字签名和证书**。
#### 数字证书和签名有什么用?
@@ -302,7 +316,7 @@ nc 127.0.0.1 8000
隐私保护?不是吓唬大家,信息是透明的兄 die,不过尽量去维护个人的隐私吧,今天学习对称加密和非对称加密。
-大家先读读这个字"钥",是读"yao",我以前也是,其实读"yue"
+大家先读读这个字“钥”,是读"yao",我以前也是,其实读"yue"
#### 什么是对称加密?
@@ -324,11 +338,11 @@ DES 使用的密钥表面上是 64 位的,然而只有其中的 56 位被实
**AES**
-当 DES 被破解以后,没过多久推出了 **AES** 算法,提供了三种长度供选择,128 位、192 位和 256,为了保证性能不受太大的影响,选择 128 即可。
+当 DES 被破解以后,没过多久推出了 **AES** 算法,提供了三种长度供选择,128 位、192 位和 256 位,为了保证性能不受太大的影响,选择 128 即可。
**SM1 和 SM4**
-之前几种都是国外的,我们国内自行研究了国密 **SM1**和 **SM4**。其中 S 都属于国家标准,算法公开。优点就是国家的大力支持和认可
+之前几种都是国外的,我们国内自行研究了国密 **SM1** 和 **SM4**。其中 S 都属于国家标准,算法公开。优点就是国家的大力支持和认可。
**总结**:
@@ -340,14 +354,13 @@ DES 使用的密钥表面上是 64 位的,然而只有其中的 56 位被实

-其实我们经常都在使用非对称加密,比如使用多台服务器搭建大数据平台 hadoop,为了方便多台机器设置免密登录,是不是就会涉及到秘钥分发。再比如搭建 docker 集群也会使用相关非对称加密算法。
+其实我们经常都在使用非对称加密,比如使用多台服务器搭建大数据平台 Hadoop,为了方便多台机器设置免密登录,是不是就会涉及到秘钥分发。再比如搭建 Docker 集群也会使用相关非对称加密算法。
常见的非对称加密算法:
-- RSA(RSA 加密算法,RSA Algorithm):优势是性能比较快,如果想要较高的加密难度,需要很长的秘钥。
-
-- ECC:基于椭圆曲线提出。是目前加密强度最高的非对称加密算法
-- SM2:同样基于椭圆曲线问题设计。最大优势就是国家认可和大力支持。
+- RSA(RSA 加密算法,RSA Algorithm):安全性基于大整数分解的计算难度,应用广泛,兼容性好。缺点是性能相对较慢,且密钥越长(如 2048/4096 位)安全性越高,但运算开销也随之增大。
+- ECC:基于椭圆曲线提出,是目前加密强度最高的非对称加密算法。
+- SM2:同样基于椭圆曲线问题设计,最大优势就是国家认可和大力支持。
总结:
@@ -357,39 +370,39 @@ DES 使用的密钥表面上是 64 位的,然而只有其中的 56 位被实
这个大家应该更加熟悉了,比如我们平常使用的 MD5 校验,在很多时候,我并不是拿来进行加密,而是用来获得唯一性 ID。在做系统的过程中,存储用户的各种密码信息,通常都会通过散列算法,最终存储其散列值。
-**MD5**
+**MD5**(不推荐)
MD5 可以用来生成一个 128 位的消息摘要,它是目前应用比较普遍的散列算法,具体的应用场景你可以自行 参阅。虽然,因为算法的缺陷,它的唯一性已经被破解了,但是大部分场景下,这并不会构成安全问题。但是,如果不是长度受限(32 个字符),我还是不推荐你继续使用 **MD5** 的。
**SHA**
-安全散列算法。**SHA** 分为 **SHA1** 和 **SH2** 两个版本。该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。
+安全散列算法。**SHA** 包括**SHA-1**、**SHA-2**和**SHA-3**三个版本。该算法的基本思想是:接收一段明文数据,通过不可逆的方式将其转换为固定长度的密文。简单来说,SHA 将输入数据(即预映射或消息)转化为固定长度、较短的输出值,称为散列值(或信息摘要、信息认证码)。SHA-1 已被证明不够安全,因此逐渐被 SHA-2 取代,而 SHA-3 则作为 SHA 系列的最新版本,采用不同的结构(Keccak 算法)提供更高的安全性和灵活性。
**SM3**
-国密算法**SM3**。加密强度和 SHA-256 想不多。主要是收到国家的支持。
+国密算法 **SM3**。加密强度和 SHA-256 算法相差不多。主要是受到了国家的支持。
**总结**:

-**大部分情况下使用对称加密,具有比较不错的安全性。如果需要分布式进行秘钥分发,考虑非对称。如果不需要可逆计算则散列算法。** 因为这段时间有这方面需求,就看了一些这方面的资料,入坑信息安全,就怕以后洗发水都不用买。谢谢大家查看!
+**大部分情况下使用对称加密,具有比较不错的安全性。如果需要分布式进行秘钥分发,考虑非对称。如果不需要可逆计算则使用散列算法。**
#### 第三方机构和证书机制有什么用?
-问题还有,此时如果 Sum 否认给过 Mike 的公钥和合同,不久 gg 了
+问题还有,此时如果 Sum 否认给过 Mike 的公钥和合同,不久就麻烦了。
-所以需要 Sum 过的话做过的事儿需要足够的信誉,这就引入了 **第三方机构和证书机制** 。
+所以需要 Sum 过的话做过的事儿需要足够的信誉,这就引入了**第三方机构和证书机制**。
-证书之所以会有信用,是因为证书的签发方拥有信用。所以如果 Sum 想让 Mike 承认自己的公钥,Sum 不会直接将公钥给 Mike ,而是提供由第三方机构,含有公钥的证书。如果 Mike 也信任这个机构,法律都认可,那 ik,信任关系成立
+证书之所以会有信用,是因为证书的签发方拥有信用。所以如果 Sum 想让 Mike 承认自己的公钥,Sum 不会直接将公钥给 Mike,而是提供由第三方机构签发的含有公钥的证书。如果 Mike 也信任这个机构,法律都认可,那信任关系成立。

如上图所示,Sum 将自己的申请提交给机构,产生证书的原文。机构用自己的私钥签名 Sum 的申请原文(先根据原文内容计算摘要,再用私钥加密),得到带有签名信息的证书。Mike 拿到带签名信息的证书,通过第三方机构的公钥进行解密,获得 Sum 证书的摘要、证书的原文。有了 Sum 证书的摘要和原文,Mike 就可以进行验签。验签通过,Mike 就可以确认 Sum 的证书的确是第三方机构签发的。
-用上面这样一个机制,合同的双方都无法否认合同。这个解决方案的核心在于需要第三方信用服务机构提供信用背书。这里产生了一个最基础的信任链,如果第三方机构的信任崩溃,比如被黑客攻破,那整条信任链条也就断裂了
+用上面这样一个机制,合同的双方都无法否认合同。这个解决方案的核心在于需要第三方信用服务机构提供信用背书。这里产生了一个最基础的信任链,如果第三方机构的信任崩溃,比如被黑客攻破,那整条信任链条也就断裂了。
-为了让这个信任条更加稳固,就需要环环相扣,打造更长的信任链,避免单点信任风险
+为了让这个信任条更加稳固,就需要环环相扣,打造更长的信任链,避免单点信任风险。

@@ -399,11 +412,11 @@ MD5 可以用来生成一个 128 位的消息摘要,它是目前应用比较
如果要验证三级机构证书的合法性,就需要用二级机构的证书去解密三级机构证书的数字签名。
-如果要验证二级结构证书的合法性,就需要用根证书去解密。
+如果要验证二级机构证书的合法性,就需要用根证书去解密。
以上,就构成了一个相对长一些的信任链。如果其中一方想要作弊是非常困难的,除非链条中的所有机构同时联合起来,进行欺诈。
-### 中间人攻击如何避免?
+### 中间人攻击如何避免?
既然知道了中间人攻击的原理也知道了他的危险,现在我们看看如何避免。相信我们都遇到过下面这种状况:
@@ -416,9 +429,9 @@ MD5 可以用来生成一个 128 位的消息摘要,它是目前应用比较
- 客户端不要轻易相信证书:因为这些证书极有可能是中间人。
- App 可以提前预埋证书在本地:意思是我们本地提前有一些证书,这样其他证书就不能再起作用了。
-## DDOS
+## DDoS
-通过上面的描述,总之即好多种攻击都是 **DDOS** 攻击,所以简单总结下这个攻击相关内容。
+通过上面的描述,前面好多种攻击都属于 DDoS 攻击,所以简单总结一下这个攻击的相关内容。
其实,像全球互联网各大公司,均遭受过大量的 **DDoS**。
@@ -442,7 +455,7 @@ DDos 全名 Distributed Denial of Service,翻译成中文就是**分布式拒
还是拿开的重庆火锅店举例,高防服务器就是我给重庆火锅店增加了两名保安,这两名保安可以让保护店铺不受流氓骚扰,并且还会定期在店铺周围巡逻防止流氓骚扰。
-高防服务器主要是指能独立硬防御 50Gbps 以上的服务器,能够帮助网站拒绝服务攻击,定期扫描网络主节点等,这东西是不错,就是贵~
+高防服务器主要是指能独立硬防御 50Gbps 以上的服务器,能够帮助网站拒绝服务攻击,定期扫描网络主节点等。
#### 黑名单
diff --git a/docs/cs-basics/network/osi-and-tcp-ip-model.md b/docs/cs-basics/network/osi-and-tcp-ip-model.md
index 34092a336b6..1456e3b9575 100644
--- a/docs/cs-basics/network/osi-and-tcp-ip-model.md
+++ b/docs/cs-basics/network/osi-and-tcp-ip-model.md
@@ -1,10 +1,26 @@
---
-title: OSI 和 TCP/IP 网络分层模型详解(基础)
+title: OSI 七层模型与 TCP/IP 四层模型详解
+description: 详解 OSI 与 TCP/IP 的分层模型与职责划分,结合历史与实践对比两者差异与工程取舍。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: OSI 七层,TCP/IP 四层,分层模型,职责划分,协议栈,对比
---
+网络分层是学习计算机网络的第一张地图。没有这张地图,HTTP、TCP、IP、以太网、DNS 这些概念很容易堆在一起,分不清谁依赖谁、谁负责什么。
+
+常见的两套分层模型是 OSI 七层模型和 TCP/IP 四层模型。前者更适合建立概念框架,后者更贴近互联网实际落地。
+
+这篇文章主要回答几个问题:
+
+1. OSI 七层模型每一层分别做什么?
+2. TCP/IP 四层模型和 OSI 七层模型如何对应?
+3. 为什么 OSI 模型理论完整,但实际没有成为互联网主流实现?
+4. 学习具体网络协议时,为什么要先知道它位于哪一层?
+
## OSI 七层模型
**OSI 七层模型** 是国际标准化组织提出一个网络分层模型,其大体结构以及每一层提供的功能如下图所示:
@@ -19,7 +35,7 @@ tag:

-**既然 OSI 七层模型这么厉害,为什么干不过 TCP/IP 四 层模型呢?**
+**既然 OSI 七层模型这么厉害,为什么干不过 TCP/IP 四层模型呢?**
的确,OSI 七层模型当时一直被一些大公司甚至一些国家政府支持。这样的背景下,为什么会失败呢?我觉得主要有下面几方面原因:
@@ -36,7 +52,7 @@ OSI 七层模型虽然失败了,但是却提供了很多不错的理论基础
## TCP/IP 四层模型
-**TCP/IP 四层模型** 是目前被广泛采用的一种模型,我们可以将 TCP / IP 模型看作是 OSI 七层模型的精简版本,由以下 4 层组成:
+**TCP/IP 四层模型** 是目前被广泛采用的一种模型,我们可以将 TCP/IP 模型看作是 OSI 七层模型的精简版本,由以下 4 层组成:
1. 应用层
2. 传输层
@@ -62,11 +78,11 @@ OSI 七层模型虽然失败了,但是却提供了很多不错的理论基础
- **HTTP(Hypertext Transfer Protocol,超文本传输协议)**:基于 TCP 协议,是一种用于传输超文本和多媒体内容的协议,主要是为 Web 浏览器与 Web 服务器之间的通信而设计的。当我们使用浏览器浏览网页的时候,我们网页就是通过 HTTP 请求进行加载的。
- **SMTP(Simple Mail Transfer Protocol,简单邮件发送协议)**:基于 TCP 协议,是一种用于发送电子邮件的协议。注意 ⚠️:SMTP 协议只负责邮件的发送,而不是接收。要从邮件服务器接收邮件,需要使用 POP3 或 IMAP 协议。
- **POP3/IMAP(邮件接收协议)**:基于 TCP 协议,两者都是负责邮件接收的协议。IMAP 协议是比 POP3 更新的协议,它在功能和性能上都更加强大。IMAP 支持邮件搜索、标记、分类、归档等高级功能,而且可以在多个设备之间同步邮件状态。几乎所有现代电子邮件客户端和服务器都支持 IMAP。
-- **FTP(File Transfer Protocol,文件传输协议)** : 基于 TCP 协议,是一种用于在计算机之间传输文件的协议,可以屏蔽操作系统和文件存储方式。注意 ⚠️:FTP 是一种不安全的协议,因为它在传输过程中不会对数据进行加密。建议在传输敏感数据时使用更安全的协议,如 SFTP。
+- **FTP(File Transfer Protocol,文件传输协议)**:基于 TCP 协议,是一种用于在计算机之间传输文件的协议,可以屏蔽操作系统和文件存储方式。注意 ⚠️:FTP 是一种不安全的协议,因为它在传输过程中不会对数据进行加密。建议在传输敏感数据时使用更安全的协议,如 SFTP。
- **Telnet(远程登陆协议)**:基于 TCP 协议,用于通过一个终端登陆到其他服务器。Telnet 协议的最大缺点之一是所有数据(包括用户名和密码)均以明文形式发送,这有潜在的安全风险。这就是为什么如今很少使用 Telnet,而是使用一种称为 SSH 的非常安全的网络传输协议的主要原因。
- **SSH(Secure Shell Protocol,安全的网络传输协议)**:基于 TCP 协议,通过加密和认证机制实现安全的访问和文件传输等业务
- **RTP(Real-time Transport Protocol,实时传输协议)**:通常基于 UDP 协议,但也支持 TCP 协议。它提供了端到端的实时传输数据的功能,但不包含资源预留存、不保证实时传输质量,这些功能由 WebRTC 实现。
-- **DNS(Domain Name System,域名管理系统)**: 基于 UDP 协议,用于解决域名和 IP 地址的映射问题。
+- **DNS(Domain Name System,域名管理系统)**:通常基于 UDP 协议(端口 53),用于解决域名和 IP 地址的映射问题。当响应数据过大或进行区域传送时会改用 TCP。
关于这些协议的详细介绍请看 [应用层常见协议总结(应用层)](./application-layer-protocol.md) 这篇文章。
@@ -95,14 +111,14 @@ OSI 七层模型虽然失败了,但是却提供了很多不错的理论基础
**网络层常见协议**:
-
+
- **IP(Internet Protocol,网际协议)**:TCP/IP 协议中最重要的协议之一,主要作用是定义数据包的格式、对数据包进行路由和寻址,以便它们可以跨网络传播并到达正确的目的地。目前 IP 协议主要分为两种,一种是过去的 IPv4,另一种是较新的 IPv6,目前这两种协议都在使用,但后者已经被提议来取代前者。
- **ARP(Address Resolution Protocol,地址解析协议)**:ARP 协议解决的是网络层地址和链路层地址之间的转换问题。因为一个 IP 数据报在物理上传输的过程中,总是需要知道下一跳(物理上的下一个目的地)该去往何处,但 IP 地址属于逻辑地址,而 MAC 地址才是物理地址,ARP 协议解决了 IP 地址转 MAC 地址的一些问题。
- **ICMP(Internet Control Message Protocol,互联网控制报文协议)**:一种用于传输网络状态和错误消息的协议,常用于网络诊断和故障排除。例如,Ping 工具就使用了 ICMP 协议来测试网络连通性。
- **NAT(Network Address Translation,网络地址转换协议)**:NAT 协议的应用场景如同它的名称——网络地址转换,应用于内部网到外部网的地址转换过程中。具体地说,在一个小的子网(局域网,LAN)内,各主机使用的是同一个 LAN 下的 IP 地址,但在该 LAN 以外,在广域网(WAN)中,需要一个统一的 IP 地址来标识该 LAN 在整个 Internet 上的位置。
-- **OSPF(Open Shortest Path First,开放式最短路径优先)** ):一种内部网关协议(Interior Gateway Protocol,IGP),也是广泛使用的一种动态路由协议,基于链路状态算法,考虑了链路的带宽、延迟等因素来选择最佳路径。
-- **RIP(Routing Information Protocol,路由信息协议)**:一种内部网关协议(Interior Gateway Protocol,IGP),也是一种动态路由协议,基于距离向量算法,使用固定的跳数作为度量标准,选择跳数最少的路径作为最佳路径。
+- **OSPF(Open Shortest Path First,开放式最短路径优先)**:一种内部网关协议(Interior Gateway Protocol,IGP),也是广泛使用的一种动态路由协议,基于链路状态算法,考虑了链路的带宽、延迟等因素来选择最佳路径。
+- **RIP(Routing Information Protocol,路由信息协议)**:一种内部网关协议(Interior Gateway Protocol,IGP),也是一种动态路由协议,基于距离向量算法,使用固定的跳数作为度量标准,选择跳数最少的路径作为最佳路径。
- **BGP(Border Gateway Protocol,边界网关协议)**:一种用来在路由选择域之间交换网络层可达性信息(Network Layer Reachability Information,NLRI)的路由选择协议,具有高度的灵活性和可扩展性。
### 网络接口层(Network interface layer)
@@ -122,7 +138,7 @@ OSI 七层模型虽然失败了,但是却提供了很多不错的理论基础

-**应用层协议** :
+**应用层协议**:
- HTTP(Hypertext Transfer Protocol,超文本传输协议)
- SMTP(Simple Mail Transfer Protocol,简单邮件发送协议)
@@ -134,7 +150,7 @@ OSI 七层模型虽然失败了,但是却提供了很多不错的理论基础
- DNS(Domain Name System,域名管理系统)
- ……
-**传输层协议** :
+**传输层协议**:
- TCP 协议
- 报文段结构
@@ -145,18 +161,18 @@ OSI 七层模型虽然失败了,但是却提供了很多不错的理论基础
- 报文段结构
- RDT(可靠数据传输协议)
-**网络层协议** :
+**网络层协议**:
- IP(Internet Protocol,网际协议)
- ARP(Address Resolution Protocol,地址解析协议)
- ICMP 协议(控制报文协议,用于发送控制消息)
- NAT(Network Address Translation,网络地址转换协议)
- OSPF(Open Shortest Path First,开放式最短路径优先)
-- RIP(Routing Information Protocol,路由信息协议)
+- RIP(Routing Information Protocol,路由信息协议)
- BGP(Border Gateway Protocol,边界网关协议)
- ……
-**网络接口层** :
+**网络接口层**:
- 差错检测技术
- 多路访问协议(信道复用技术)
diff --git a/docs/cs-basics/network/other-network-questions.md b/docs/cs-basics/network/other-network-questions.md
index f9f91f45e12..d3760dfa00c 100644
--- a/docs/cs-basics/network/other-network-questions.md
+++ b/docs/cs-basics/network/other-network-questions.md
@@ -1,13 +1,20 @@
---
title: 计算机网络常见面试题总结(上)
+description: 最新计算机网络高频面试题总结(上):TCP/IP四层模型、HTTP全版本对比、TCP三次握手、DNS解析、WebSocket/SSE实时推送等,附图解+⭐️重点标注,一文搞定应用层&传输层&网络层核心考点,快速备战后端面试!
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: 计算机网络面试题,TCP/IP四层模型,HTTP面试,HTTPS vs HTTP,HTTP/1.1 vs HTTP/2,HTTP/3 QUIC,TCP三次握手,UDP区别,DNS解析,WebSocket vs SSE,GET vs POST,应用层协议,网络分层,队头阻塞,PING命令,ARP协议
---
-
+
-上篇主要是计算机网络基础和应用层相关的内容。
+计算机网络是后端面试和校招面试中绕不开的高频考点,尤其是 **TCP/IP 网络分层、HTTP、HTTPS、DNS、WebSocket、TCP 三次握手** 这些问题,几乎贯穿了“从输入 URL 到页面展示”“接口为什么变慢”“连接为什么失败”等真实开发场景。
+
+这篇《计算机网络常见面试题总结(上)》会先从网络分层模型讲起,再梳理应用层和 HTTP 相关的核心知识点,适合用来系统复习计算机网络基础,也适合作为 Java 后端、后端开发、计算机基础面试前的速查清单。
## 计算机网络基础
@@ -27,9 +34,9 @@ tag:

-#### TCP/IP 四层模型是什么?每一层的作用是什么?
+#### ⭐️TCP/IP 四层模型是什么?每一层的作用是什么?
-**TCP/IP 四层模型** 是目前被广泛采用的一种模型,我们可以将 TCP / IP 模型看作是 OSI 七层模型的精简版本,由以下 4 层组成:
+**TCP/IP 四层模型** 是目前被广泛采用的一种模型,我们可以将 TCP/IP 模型看作是 OSI 七层模型的精简版本,由以下 4 层组成:
1. 应用层
2. 传输层
@@ -40,7 +47,7 @@ tag:

-关于每一层作用的详细介绍,请看 [OSI 和 TCP/IP 网络分层模型详解(基础)](./osi-and-tcp-ip-model.md) 这篇文章。
+关于每一层作用的详细介绍,请看 [OSI 和 TCP/IP 网络分层模型详解(基础)](https://javaguide.cn/cs-basics/network/osi-and-tcp-ip-model.html) 这篇文章。
#### 为什么网络要分层?
@@ -64,18 +71,18 @@ tag:
### 常见网络协议
-#### 应用层有哪些常见的协议?
+#### ⭐️应用层有哪些常见的协议?

- **HTTP(Hypertext Transfer Protocol,超文本传输协议)**:基于 TCP 协议,是一种用于传输超文本和多媒体内容的协议,主要是为 Web 浏览器与 Web 服务器之间的通信而设计的。当我们使用浏览器浏览网页的时候,我们网页就是通过 HTTP 请求进行加载的。
- **SMTP(Simple Mail Transfer Protocol,简单邮件发送协议)**:基于 TCP 协议,是一种用于发送电子邮件的协议。注意 ⚠️:SMTP 协议只负责邮件的发送,而不是接收。要从邮件服务器接收邮件,需要使用 POP3 或 IMAP 协议。
- **POP3/IMAP(邮件接收协议)**:基于 TCP 协议,两者都是负责邮件接收的协议。IMAP 协议是比 POP3 更新的协议,它在功能和性能上都更加强大。IMAP 支持邮件搜索、标记、分类、归档等高级功能,而且可以在多个设备之间同步邮件状态。几乎所有现代电子邮件客户端和服务器都支持 IMAP。
-- **FTP(File Transfer Protocol,文件传输协议)** : 基于 TCP 协议,是一种用于在计算机之间传输文件的协议,可以屏蔽操作系统和文件存储方式。注意 ⚠️:FTP 是一种不安全的协议,因为它在传输过程中不会对数据进行加密。建议在传输敏感数据时使用更安全的协议,如 SFTP。
+- **FTP(File Transfer Protocol,文件传输协议)**:基于 TCP 协议,是一种用于在计算机之间传输文件的协议,可以屏蔽操作系统和文件存储方式。注意 ⚠️:FTP 是一种不安全的协议,因为它在传输过程中不会对数据进行加密。建议在传输敏感数据时使用更安全的协议,如 SFTP。
- **Telnet(远程登陆协议)**:基于 TCP 协议,用于通过一个终端登陆到其他服务器。Telnet 协议的最大缺点之一是所有数据(包括用户名和密码)均以明文形式发送,这有潜在的安全风险。这就是为什么如今很少使用 Telnet,而是使用一种称为 SSH 的非常安全的网络传输协议的主要原因。
- **SSH(Secure Shell Protocol,安全的网络传输协议)**:基于 TCP 协议,通过加密和认证机制实现安全的访问和文件传输等业务
- **RTP(Real-time Transport Protocol,实时传输协议)**:通常基于 UDP 协议,但也支持 TCP 协议。它提供了端到端的实时传输数据的功能,但不包含资源预留存、不保证实时传输质量,这些功能由 WebRTC 实现。
-- **DNS(Domain Name System,域名管理系统)**: 基于 UDP 协议,用于解决域名和 IP 地址的映射问题。
+- **DNS(Domain Name System,域名管理系统)**:通常基于 UDP 协议(端口 53),用于解决域名和 IP 地址的映射问题。当响应数据过大或进行区域传送时会改用 TCP。
关于这些协议的详细介绍请看 [应用层常见协议总结(应用层)](./application-layer-protocol.md) 这篇文章。
@@ -88,19 +95,19 @@ tag:
#### 网络层有哪些常见的协议?
-
+
- **IP(Internet Protocol,网际协议)**:TCP/IP 协议中最重要的协议之一,属于网络层的协议,主要作用是定义数据包的格式、对数据包进行路由和寻址,以便它们可以跨网络传播并到达正确的目的地。目前 IP 协议主要分为两种,一种是过去的 IPv4,另一种是较新的 IPv6,目前这两种协议都在使用,但后者已经被提议来取代前者。
- **ARP(Address Resolution Protocol,地址解析协议)**:ARP 协议解决的是网络层地址和链路层地址之间的转换问题。因为一个 IP 数据报在物理上传输的过程中,总是需要知道下一跳(物理上的下一个目的地)该去往何处,但 IP 地址属于逻辑地址,而 MAC 地址才是物理地址,ARP 协议解决了 IP 地址转 MAC 地址的一些问题。
- **ICMP(Internet Control Message Protocol,互联网控制报文协议)**:一种用于传输网络状态和错误消息的协议,常用于网络诊断和故障排除。例如,Ping 工具就使用了 ICMP 协议来测试网络连通性。
- **NAT(Network Address Translation,网络地址转换协议)**:NAT 协议的应用场景如同它的名称——网络地址转换,应用于内部网到外部网的地址转换过程中。具体地说,在一个小的子网(局域网,LAN)内,各主机使用的是同一个 LAN 下的 IP 地址,但在该 LAN 以外,在广域网(WAN)中,需要一个统一的 IP 地址来标识该 LAN 在整个 Internet 上的位置。
-- **OSPF(Open Shortest Path First,开放式最短路径优先)** ):一种内部网关协议(Interior Gateway Protocol,IGP),也是广泛使用的一种动态路由协议,基于链路状态算法,考虑了链路的带宽、延迟等因素来选择最佳路径。
-- **RIP(Routing Information Protocol,路由信息协议)**:一种内部网关协议(Interior Gateway Protocol,IGP),也是一种动态路由协议,基于距离向量算法,使用固定的跳数作为度量标准,选择跳数最少的路径作为最佳路径。
+- **OSPF(Open Shortest Path First,开放式最短路径优先)**:一种内部网关协议(Interior Gateway Protocol,IGP),也是广泛使用的一种动态路由协议,基于链路状态算法,考虑了链路的带宽、延迟等因素来选择最佳路径。
+- **RIP(Routing Information Protocol,路由信息协议)**:一种内部网关协议(Interior Gateway Protocol,IGP),也是一种动态路由协议,基于距离向量算法,使用固定的跳数作为度量标准,选择跳数最少的路径作为最佳路径。
- **BGP(Border Gateway Protocol,边界网关协议)**:一种用来在路由选择域之间交换网络层可达性信息(Network Layer Reachability Information,NLRI)的路由选择协议,具有高度的灵活性和可扩展性。
## HTTP
-### 从输入 URL 到页面展示到底发生了什么?(非常重要)
+### ⭐️从输入 URL 到页面展示到底发生了什么?(非常重要)
> 类似的问题:打开一个网页,整个过程会使用哪些协议?
@@ -120,54 +127,54 @@ tag:
6. 浏览器收到 HTTP 响应报文后,解析响应体中的 HTML 代码,渲染网页的结构和样式,同时根据 HTML 中的其他资源的 URL(如图片、CSS、JS 等),再次发起 HTTP 请求,获取这些资源的内容,直到网页完全加载显示。
7. 浏览器在不需要和服务器通信时,可以主动关闭 TCP 连接,或者等待服务器的关闭请求。
-详细介绍可以查看这篇文章:[访问网页的全过程(知识串联)](./the-whole-process-of-accessing-web-pages.md)(强烈推荐)。
+详细介绍可以查看这篇文章:[访问网页的全过程(知识串联)](https://javaguide.cn/cs-basics/network/the-whole-process-of-accessing-web-pages.html)(强烈推荐)。
-### HTTP 状态码有哪些?
+### ⭐️HTTP 状态码有哪些?
HTTP 状态码用于描述 HTTP 请求的结果,比如 2xx 就代表请求被成功处理。

-关于 HTTP 状态码更详细的总结,可以看我写的这篇文章:[HTTP 常见状态码总结(应用层)](./http-status-codes.md)。
+关于 HTTP 状态码更详细的总结,可以看我写的这篇文章:[HTTP 常见状态码总结(应用层)](https://javaguide.cn/cs-basics/network/http-status-codes.html)。
### HTTP Header 中常见的字段有哪些?
-| 请求头字段名 | 说明 | 示例 |
-| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------- |
-| Accept | 能够接受的回应内容类型(Content-Types)。 | Accept: text/plain |
-| Accept-Charset | 能够接受的字符集 | Accept-Charset: utf-8 |
-| Accept-Datetime | 能够接受的按照时间来表示的版本 | Accept-Datetime: Thu, 31 May 2007 20:35:00 GMT |
-| Accept-Encoding | 能够接受的编码方式列表。参考 HTTP 压缩。 | Accept-Encoding: gzip, deflate |
-| Accept-Language | 能够接受的回应内容的自然语言列表。 | Accept-Language: en-US |
-| Authorization | 用于超文本传输协议的认证的认证信息 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
-| Cache-Control | 用来指定在这次的请求/响应链中的所有缓存机制 都必须 遵守的指令 | Cache-Control: no-cache |
-| Connection | 该浏览器想要优先使用的连接类型 | Connection: keep-alive Connection: Upgrade |
-| Content-Length | 以 八位字节数组 (8 位的字节)表示的请求体的长度 | Content-Length: 348 |
-| Content-MD5 | 请求体的内容的二进制 MD5 散列值,以 Base64 编码的结果 | Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== |
-| Content-Type | 请求体的 多媒体类型 (用于 POST 和 PUT 请求中) | Content-Type: application/x-www-form-urlencoded |
-| Cookie | 之前由服务器通过 Set- Cookie (下文详述)发送的一个 超文本传输协议 Cookie | Cookie: \$Version=1; Skin=new; |
-| Date | 发送该消息的日期和时间(按照 RFC 7231 中定义的"超文本传输协议日期"格式来发送) | Date: Tue, 15 Nov 1994 08:12:31 GMT |
-| Expect | 表明客户端要求服务器做出特定的行为 | Expect: 100-continue |
-| From | 发起此请求的用户的邮件地址 | From: [user@example.com](mailto:user@example.com) |
-| Host | 服务器的域名(用于虚拟主机 ),以及服务器所监听的传输控制协议端口号。如果所请求的端口是对应的服务的标准端口,则端口号可被省略。 | Host: en.wikipedia.org:80 |
-| If-Match | 仅当客户端提供的实体与服务器上对应的实体相匹配时,才进行对应的操作。主要作用时,用作像 PUT 这样的方法中,仅当从用户上次更新某个资源以来,该资源未被修改的情况下,才更新该资源。 | If-Match: “737060cd8c284d8af7ad3082f209582d” |
-| If-Modified-Since | 允许在对应的内容未被修改的情况下返回 304 未修改( 304 Not Modified ) | If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT |
-| If-None-Match | 允许在对应的内容未被修改的情况下返回 304 未修改( 304 Not Modified ) | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
-| If-Range | 如果该实体未被修改过,则向我发送我所缺少的那一个或多个部分;否则,发送整个新的实体 | If-Range: “737060cd8c284d8af7ad3082f209582d” |
-| If-Unmodified-Since | 仅当该实体自某个特定时间已来未被修改的情况下,才发送回应。 | If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT |
-| Max-Forwards | 限制该消息可被代理及网关转发的次数。 | Max-Forwards: 10 |
-| Origin | 发起一个针对 跨来源资源共享 的请求。 | Origin: [http://www.example-social-network.com](http://www.example-social-network.com/) |
-| Pragma | 与具体的实现相关,这些字段可能在请求/回应链中的任何时候产生多种效果。 | Pragma: no-cache |
-| Proxy-Authorization | 用来向代理进行认证的认证信息。 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
-| Range | 仅请求某个实体的一部分。字节偏移以 0 开始。参见字节服务。 | Range: bytes=500-999 |
-| Referer | 表示浏览器所访问的前一个页面,正是那个页面上的某个链接将浏览器带到了当前所请求的这个页面。 | Referer: [http://en.wikipedia.org/wiki/Main_Page](https://en.wikipedia.org/wiki/Main_Page) |
-| TE | 浏览器预期接受的传输编码方式:可使用回应协议头 Transfer-Encoding 字段中的值; | TE: trailers, deflate |
-| Upgrade | 要求服务器升级到另一个协议。 | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
-| User-Agent | 浏览器的浏览器身份标识字符串 | User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0 |
-| Via | 向服务器告知,这个请求是由哪些代理发出的。 | Via: 1.0 fred, 1.1 example.com (Apache/1.1) |
-| Warning | 一个一般性的警告,告知,在实体内容体中可能存在错误。 | Warning: 199 Miscellaneous warning |
-
-### HTTP 和 HTTPS 有什么区别?(重要)
+| 请求头字段名 | 说明 | 示例 |
+| :------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------- |
+| Accept | 能够接受的回应内容类型(Content-Types)。 | Accept: text/plain |
+| Accept-Charset | 能够接受的字符集 | Accept-Charset: utf-8 |
+| Accept-Datetime | 能够接受的按照时间来表示的版本 | Accept-Datetime: Thu, 31 May 2007 20:35:00 GMT |
+| Accept-Encoding | 能够接受的编码方式列表。参考 HTTP 压缩。 | Accept-Encoding: gzip, deflate |
+| Accept-Language | 能够接受的回应内容的自然语言列表。 | Accept-Language: en-US |
+| Authorization | 用于超文本传输协议的认证的认证信息 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
+| Cache-Control | 用来指定在这次的请求/响应链中的所有缓存机制 都必须 遵守的指令 | Cache-Control: no-cache |
+| Connection | 该浏览器想要优先使用的连接类型 | Connection: keep-alive |
+| Content-Length | 以八位字节数组(8 位的字节)表示的请求体的长度 | Content-Length: 348 |
+| Content-MD5 | 请求体的内容的二进制 MD5 散列值,以 Base64 编码的结果 | Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== |
+| Content-Type | 请求体的多媒体类型(用于 POST 和 PUT 请求中) | Content-Type: application/x-www-form-urlencoded |
+| Cookie | 之前由服务器通过 Set-Cookie(下文详述)发送的一个超文本传输协议 Cookie | Cookie: $Version=1; Skin=new; |
+| Date | 发送该消息的日期和时间(按照 RFC 7231 中定义的“超文本传输协议日期”格式来发送) | Date: Tue, 15 Nov 1994 08:12:31 GMT |
+| Expect | 表明客户端要求服务器做出特定的行为 | Expect: 100-continue |
+| From | 发起此请求的用户的邮件地址 | From: `user@example.com` |
+| Host | 服务器的域名(用于虚拟主机),以及服务器所监听的传输控制协议端口号。如果所请求的端口是对应的服务的标准端口,则端口号可被省略。 | Host: en.wikipedia.org |
+| If-Match | 仅当客户端提供的实体与服务器上对应的实体相匹配时,才进行对应的操作。主要作用是用于像 PUT 这样的方法中,仅当从用户上次更新某个资源以来,该资源未被修改的情况下,才更新该资源。 | If-Match: "737060cd8c284d8af7ad3082f209582d" |
+| If-Modified-Since | 允许服务器在请求的资源自指定的日期以来未被修改的情况下返回 `304 Not Modified` 状态码 | If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT |
+| If-None-Match | 允许服务器在请求的资源的 ETag 未发生变化的情况下返回 `304 Not Modified` 状态码 | If-None-Match: "737060cd8c284d8af7ad3082f209582d" |
+| If-Range | 如果该实体未被修改过,则向我发送我所缺少的那一个或多个部分;否则,发送整个新的实体 | If-Range: "737060cd8c284d8af7ad3082f209582d" |
+| If-Unmodified-Since | 仅当该实体自某个特定时间以来未被修改的情况下,才发送回应。 | If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT |
+| Max-Forwards | 限制该消息可被代理及网关转发的次数。 | Max-Forwards: 10 |
+| Origin | 发起一个针对跨来源资源共享的请求。 | `Origin: http://www.example-social-network.com` |
+| Pragma | 与具体的实现相关,这些字段可能在请求/回应链中的任何时候产生多种效果。 | Pragma: no-cache |
+| Proxy-Authorization | 用来向代理进行认证的认证信息。 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
+| Range | 仅请求某个实体的一部分。字节偏移以 0 开始。参见字节服务。 | Range: bytes=500-999 |
+| Referer | 表示浏览器所访问的前一个页面,正是那个页面上的某个链接将浏览器带到了当前所请求的这个页面。 | `Referer: http://en.wikipedia.org/wiki/Main_Page` |
+| TE | 浏览器预期接受的传输编码方式:可使用回应协议头 Transfer-Encoding 字段中的值; | TE: trailers, deflate |
+| Upgrade | 要求服务器升级到另一个协议。 | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
+| User-Agent | 浏览器的浏览器身份标识字符串 | User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0 |
+| Via | 向服务器告知,这个请求是由哪些代理发出的。 | Via: 1.0 fred, 1.1 example.com (Apache/1.1) |
+| Warning | 一个一般性的警告,告知,在实体内容体中可能存在错误。 | Warning: 199 Miscellaneous warning |
+
+### ⭐️HTTP 和 HTTPS 有什么区别?(重要)

@@ -176,26 +183,60 @@ HTTP 状态码用于描述 HTTP 请求的结果,比如 2xx 就代表请求被
- **安全性和资源消耗**:HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。HTTPS 是运行在 SSL/TLS 之上的 HTTP 协议,SSL/TLS 运行在 TCP 之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。所以说,HTTP 安全性没有 HTTPS 高,但是 HTTPS 比 HTTP 耗费更多服务器资源。
- **SEO(搜索引擎优化)**:搜索引擎通常会更青睐使用 HTTPS 协议的网站,因为 HTTPS 能够提供更高的安全性和用户隐私保护。使用 HTTPS 协议的网站在搜索结果中可能会被优先显示,从而对 SEO 产生影响。
-关于 HTTP 和 HTTPS 更详细的对比总结,可以看我写的这篇文章:[HTTP vs HTTPS(应用层)](./http-vs-https.md) 。
+关于 HTTP 和 HTTPS 更详细的对比总结,可以看我写的这篇文章:[HTTP vs HTTPS(应用层)](https://javaguide.cn/cs-basics/network/http-vs-https.html) 。
+
+### HTTPS 握手里的 RSA 和 ECDHE,到底差在哪?(应用层)
+
+RSA 和 ECDHE 的核心区别在于:**会话密钥材料是“传过去的”,还是“协商出来的”**。
+
+在 TLS 1.2 的静态 RSA 握手里,客户端生成 `PreMasterSecret`,用服务器证书里的 RSA 公钥加密后发给服务端,服务端再用 RSA 私钥解密。问题是,如果攻击者保存了当年的握手流量,后来服务器私钥又泄漏,就可能回头解出历史会话密钥,所以它没有前向安全。
+
+ECDHE 不直接传输共享秘密。客户端和服务端各自生成临时密钥对,交换临时公钥后,双方本地算出同一个共享秘密。服务器证书私钥主要用于签名认证,证明临时参数没被中间人替换,而不是用来解密会话密钥。
+
+所以一句话总结:**RSA 是客户端把秘密加密送过去;ECDHE 是双方用临时密钥协商出秘密。ECDHE 支持前向安全,也因此成为现代 HTTPS 的主流方向。**
+
+详细介绍:[HTTPS 握手里的 RSA 和 ECDHE,到底差在哪?(应用层)](./https-rsa-vs-ecdhe)
+
+### ⭐️有了HTTP,为什么还要RPC?
+
+HTTP 和 RPC 不是谁取代谁的关系,也不是谁更高级的问题。
+
+HTTP 能调服务,RPC 也能调服务。真正的区别在于,你是想把远程调用当成一次“资源访问”,还是当成一次“方法调用”。
+
+如果是对外接口,比如 Web、App、第三方系统接入,HTTP 通常更合适。它通用、好调试、接入成本低,别人拿 Postman、curl 就能测。
+如果是公司内部服务互调,尤其是服务多、调用链长、接口频繁调用,还要考虑服务发现、超时、重试、负载均衡、链路追踪这些问题,RPC 会更顺手一些。它不是单纯为了快,而是把内部服务调用里的很多麻烦事一起处理掉。
+
+所以,别再简单背“HTTP 对外,RPC 对内”了。
+
+这句话可以帮助入门,但真做项目时,还得看你的调用对象、团队基础设施、排查成本、性能要求和后续维护成本。
+
+系统规模不大,用 HTTP 已经跑得很稳,就别为了“看起来更微服务”强上 RPC。
+
+内部调用越来越复杂,HTTP SDK、网关、监控、重试这些东西越补越多,那就可以认真考虑 RPC。
+
+一句话:**HTTP 没那么弱,RPC 也没那么神。选哪个,主要看它能不能用更低成本解决你现在的问题。**
+
+详细介绍:[⭐️有了HTTP,为什么还要RPC?](./http-vs-rpc.md)
### HTTP/1.0 和 HTTP/1.1 有什么区别?

-- **连接方式** : HTTP/1.0 为短连接,HTTP/1.1 支持长连接。HTTP 协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接。
-- **状态响应码** : HTTP/1.1 中新加入了大量的状态码,光是错误响应状态码就新增了 24 种。比如说,`100 (Continue)`——在请求大资源前的预热请求,`206 (Partial Content)`——范围请求的标识码,`409 (Conflict)`——请求与当前资源的规定冲突,`410 (Gone)`——资源已被永久转移,而且没有任何已知的转发地址。
-- **缓存机制** : 在 HTTP/1.0 中主要使用 Header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP/1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。
+- **连接方式**:HTTP/1.0 为短连接,HTTP/1.1 支持长连接。HTTP 协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接。
+- **状态响应码**:HTTP/1.1 中新加入了大量的状态码,光是错误响应状态码就新增了 24 种。比如说,`100 (Continue)`——在请求大资源前的预热请求,`206 (Partial Content)`——范围请求的标识码,`409 (Conflict)`——请求与当前资源的规定冲突,`410 (Gone)`——资源已被永久转移,而且没有任何已知的转发地址。
+- **缓存机制**:在 HTTP/1.0 中主要使用 Header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP/1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。
- **带宽**:HTTP/1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP/1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
-- **Host 头(Host Header)处理** :HTTP/1.1 引入了 Host 头字段,允许在同一 IP 地址上托管多个域名,从而支持虚拟主机的功能。而 HTTP/1.0 没有 Host 头字段,无法实现虚拟主机。
+- **Host 头(Host Header)处理**:HTTP/1.1 引入了 Host 头字段,允许在同一 IP 地址上托管多个域名,从而支持虚拟主机的功能。而 HTTP/1.0 没有 Host 头字段,无法实现虚拟主机。
-关于 HTTP/1.0 和 HTTP/1.1 更详细的对比总结,可以看我写的这篇文章:[HTTP/1.0 vs HTTP/1.1(应用层)](./http1.0-vs-http1.1.md) 。
+关于 HTTP/1.0 和 HTTP/1.1 更详细的对比总结,可以看我写的这篇文章:[HTTP/1.0 vs HTTP/1.1(应用层)](https://javaguide.cn/cs-basics/network/http1.0-vs-http1.1.html) 。
-### HTTP/1.1 和 HTTP/2.0 有什么区别?
+### ⭐️HTTP/1.1 和 HTTP/2.0 有什么区别?

-- **多路复用(Multiplexing)**:HTTP/2.0 在同一连接上可以同时传输多个请求和响应(可以看作是 HTTP/1.1 中长链接的升级版本),互不干扰。HTTP/1.1 则使用串行方式,每个请求和响应都需要独立的连接,而浏览器为了控制资源会有 6-8 个 TCP 连接都限制。。这使得 HTTP/2.0 在处理多个请求时更加高效,减少了网络延迟和提高了性能。
+- **多路复用(Multiplexing)**:HTTP/2.0 在同一连接上可以同时传输多个请求和响应(可以看作是 HTTP/1.1 中长链接的升级版本),互不干扰。HTTP/1.1 则使用串行方式,每个请求和响应都需要独立的连接,而浏览器为了控制资源会有 6-8 个 TCP 连接的限制。这使得 HTTP/2.0 在处理多个请求时更加高效,减少了网络延迟和提高了性能。
- **二进制帧(Binary Frames)**:HTTP/2.0 使用二进制帧进行数据传输,而 HTTP/1.1 则使用文本格式的报文。二进制帧更加紧凑和高效,减少了传输的数据量和带宽消耗。
+- **队头阻塞**:HTTP/2 引入了多路复用技术,允许多个请求和响应在单个 TCP 连接上并行交错传输,解决了 HTTP/1.1 应用层的队头阻塞问题,但 HTTP/2 依然受到 TCP 层队头阻塞 的影响。
- **头部压缩(Header Compression)**:HTTP/1.1 支持`Body`压缩,`Header`不支持压缩。HTTP/2.0 支持对`Header`压缩,使用了专门为`Header`压缩而设计的 HPACK 算法,减少了网络开销。
- **服务器推送(Server Push)**:HTTP/2.0 支持服务器推送,可以在客户端请求一个资源时,将其他相关资源一并推送给客户端,从而减少了客户端的请求次数和延迟。而 HTTP/1.1 需要客户端自己发送请求来获取相关资源。
@@ -203,7 +244,7 @@ HTTP/2.0 多路复用效果图(图源: [HTTP/2 For Web Developers](https://b

-可以看到,HTTP/2.0 的多路复用使得不同的请求可以共用一个 TCP 连接,避免建立多个连接带来不必要的额外开销,而 HTTP/1.1 中的每个请求都会建立一个单独的连接
+可以看到,HTTP/2 的多路复用机制允许多个请求和响应共享一个 TCP 连接,从而避免了 HTTP/1.1 在应对并发请求时需要建立多个并行连接的情况,减少了重复连接建立和维护的额外开销。而在 HTTP/1.1 中,尽管支持持久连接,但为了缓解队头阻塞问题,浏览器通常会为同一域名建立多个并行连接。
### HTTP/2.0 和 HTTP/3.0 有什么区别?
@@ -211,25 +252,110 @@ HTTP/2.0 多路复用效果图(图源: [HTTP/2 For Web Developers](https://b
- **传输协议**:HTTP/2.0 是基于 TCP 协议实现的,HTTP/3.0 新增了 QUIC(Quick UDP Internet Connections) 协议来实现可靠的传输,提供与 TLS/SSL 相当的安全性,具有较低的连接和传输延迟。你可以将 QUIC 看作是 UDP 的升级版本,在其基础上新增了很多功能比如加密、重传等等。HTTP/3.0 之前名为 HTTP-over-QUIC,从这个名字中我们也可以发现,HTTP/3 最大的改造就是使用了 QUIC。
- **连接建立**:HTTP/2.0 需要经过经典的 TCP 三次握手过程(由于安全的 HTTPS 连接建立还需要 TLS 握手,共需要大约 3 个 RTT)。由于 QUIC 协议的特性(TLS 1.3,TLS 1.3 除了支持 1 个 RTT 的握手,还支持 0 个 RTT 的握手)连接建立仅需 0-RTT 或者 1-RTT。这意味着 QUIC 在最佳情况下不需要任何的额外往返时间就可以建立新连接。
+- **头部压缩**:HTTP/2.0 使用 HPACK 算法进行头部压缩,而 HTTP/3.0 使用更高效的 QPACK 头压缩算法。
- **队头阻塞**:HTTP/2.0 多请求复用一个 TCP 连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求。由于 QUIC 协议的特性,HTTP/3.0 在一定程度上解决了队头阻塞(Head-of-Line blocking, 简写:HOL blocking)问题,一个连接建立多个不同的数据流,这些数据流之间独立互不影响,某个数据流发生丢包了,其数据流不受影响(本质上是多路复用+轮询)。
+- **连接迁移**:HTTP/3.0 支持连接迁移,因为 QUIC 使用 64 位 ID 标识连接,只要 ID 不变就不会中断,网络环境改变时(如从 Wi-Fi 切换到移动数据)也能保持连接。而 TCP 连接是由(源 IP,源端口,目的 IP,目的端口)组成,这个四元组中一旦有一项值发生改变,这个连接也就不能用了。
- **错误恢复**:HTTP/3.0 具有更好的错误恢复机制,当出现丢包、延迟等网络问题时,可以更快地进行恢复和重传。而 HTTP/2.0 则需要依赖于 TCP 的错误恢复机制。
-- **安全性**:HTTP/2.0 和 HTTP/3.0 在安全性上都有较高的要求,支持加密通信,但在实现上有所不同。HTTP/2.0 使用 TLS 协议进行加密,而 HTTP/3.0 基于 QUIC 协议,包含了内置的加密和身份验证机制,可以提供更强的安全性。
+- **安全性**:在 HTTP/2.0 中,TLS 用于加密和认证整个 HTTP 会话,包括所有的 HTTP 头部和数据负载。TLS 的工作是在 TCP 层之上,它加密的是在 TCP 连接中传输的应用层的数据,并不会对 TCP 头部以及 TLS 记录层头部进行加密,所以在传输的过程中 TCP 头部可能会被攻击者篡改来干扰通信。而 HTTP/3.0 的 QUIC 对整个数据包(包括报文头和报文体)进行了加密与认证处理,保障安全性。
HTTP/1.0、HTTP/2.0 和 HTTP/3.0 的协议栈比较:

+下图是一个更详细的 HTTP/2.0 和 HTTP/3.0 对比图:
+
+
+
+从上图可以看出:
+
+- **HTTP/2.0**:使用 TCP 作为传输协议、使用 HPACK 进行头部压缩、依赖 TLS 进行加密。
+- **HTTP/3.0**:使用基于 UDP 的 QUIC 协议、使用更高效的 QPACK 进行头部压缩、在 QUIC 中直接集成了 TLS。QUIC 协议具备连接迁移、拥塞控制与避免、流量控制等特性。
+
关于 HTTP/1.0 -> HTTP/3.0 更详细的演进介绍,推荐阅读[HTTP1 到 HTTP3 的工程优化](https://dbwu.tech/posts/http_evolution/)。
-### HTTP 是不保存状态的协议, 如何保存用户状态?
+### HTTP/1.1 和 HTTP/2.0 的队头阻塞有什么不同?
+
+HTTP/1.1 队头阻塞的主要原因是无法多路复用:
+
+- 在一个 TCP 连接中,资源的请求和响应是按顺序处理的。如果一个大的资源(如一个大文件)正在传输,后续的小资源(如较小的 CSS 文件)需要等待前面的资源传输完成后才能被发送。
+- 如果浏览器需要同时加载多个资源(如多个 CSS、JS 文件等),它通常会开启多个并行的 TCP 连接(一般限制为 6 个)。但每个连接仍然受限于顺序的请求-响应机制,因此仍然会发生 **应用层的队头阻塞**。
+
+虽然 HTTP/2.0 引入了多路复用技术,允许多个请求和响应在单个 TCP 连接上并行交错传输,解决了 **HTTP/1.1 应用层的队头阻塞问题**,但 HTTP/2.0 依然受到 **TCP 层队头阻塞** 的影响:
+
+- HTTP/2.0 通过帧(frame)机制将每个资源分割成小块,并为每个资源分配唯一的流 ID,这样多个资源的数据可以在同一 TCP 连接中交错传输。
+- TCP 作为传输层协议,要求数据按顺序交付。如果某个数据包在传输过程中丢失,即使后续的数据包已经到达,也必须等待丢失的数据包重传后才能继续处理。这种传输层的顺序性导致了 **TCP 层的队头阻塞**。
+- 举例来说,如果 HTTP/2 的一个 TCP 数据包中携带了多个资源的数据(例如 JS 和 CSS),而该数据包丢失了,那么后续数据包中的所有资源数据都需要等待丢失的数据包重传回来,导致所有流(streams)都被阻塞。
+
+最后,来一张表格总结补充一下:
+
+| **方面** | **HTTP/1.1 的队头阻塞** | **HTTP/2.0 的队头阻塞** |
+| -------------- | ---------------------------------------- | ---------------------------------------------------------------- |
+| **层级** | 应用层(HTTP 协议本身的限制) | 传输层(TCP 协议的限制) |
+| **根本原因** | 无法多路复用,请求和响应必须按顺序传输 | TCP 要求数据包按顺序交付,丢包时阻塞整个连接 |
+| **受影响范围** | 单个 HTTP 请求/响应会阻塞后续请求/响应。 | 单个 TCP 包丢失会影响所有 HTTP/2.0 流(依赖于同一个底层 TCP 连接) |
+| **缓解方法** | 开启多个并行的 TCP 连接 | 减少网络掉包或者使用基于 UDP 的 QUIC 协议 |
+| **影响场景** | 每次都会发生,尤其是大文件阻塞小文件时。 | 丢包率较高的网络环境下更容易发生。 |
+
+### ⭐️HTTP 是不保存状态的协议, 如何保存用户状态?
+
+HTTP 协议本身是 **无状态的 (stateless)** 。这意味着服务器默认情况下无法区分两个连续的请求是否来自同一个用户,或者同一个用户之前的操作是什么。这就像一个“健忘”的服务员,每次你跟他说话,他都不知道你是谁,也不知道你之前点过什么菜。
-HTTP 是一种不保存状态,即无状态(stateless)协议。也就是说 HTTP 协议自身不对请求和响应之间的通信状态进行保存。那么我们如何保存用户状态呢?Session 机制的存在就是为了解决这个问题,Session 的主要作用就是通过服务端记录用户的状态。典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了(一般情况下,服务器会在一定时间内保存这个 Session,过了时间限制,就会销毁这个 Session)。
+但在实际的 Web 应用中,比如网上购物、用户登录等场景,我们显然需要记住用户的状态(例如购物车里的商品、用户的登录信息)。为了解决这个问题,主要有以下几种常用机制:
-在服务端保存 Session 的方法很多,最常用的就是内存和数据库(比如是使用内存数据库 redis 保存)。既然 Session 存放在服务器端,那么我们如何实现 Session 跟踪呢?大部分情况下,我们都是通过在 Cookie 中附加一个 Session ID 来方式来跟踪。
+**方案一:Session (会话) 配合 Cookie (主流方式):**
-**Cookie 被禁用怎么办?**
+
-最常用的就是利用 URL 重写把 Session ID 直接附加在 URL 路径的后面。
+这可以说是最经典也是最常用的方法了。基本流程是这样的:
+
+1. 用户向服务器发送用户名、密码、验证码用于登陆系统。
+2. 服务器验证通过后,会为这个用户创建一个专属的 Session 对象(可以理解为服务器上的一块内存,存放该用户的状态数据,如购物车、登录信息等)存储起来,并给这个 Session 分配一个唯一的 `SessionID`。
+3. 服务器通过 HTTP 响应头中的 `Set-Cookie` 指令,把这个 `SessionID` 发送给用户的浏览器。
+4. 浏览器接收到 `SessionID` 后,会将其以 Cookie 的形式保存在本地。当用户保持登录状态时,每次向该服务器发请求,浏览器都会自动带上这个存有 `SessionID` 的 Cookie。
+5. 服务器收到请求后,从 Cookie 中拿出 `SessionID`,就能找到之前保存的那个 Session 对象,从而知道这是哪个用户以及他之前的状态了。
+
+使用 Session 的时候需要注意下面几个点:
+
+- **客户端 Cookie 支持**:依赖 Session 的核心功能要确保用户浏览器开启了 Cookie。
+- **Session 过期管理**:合理设置 Session 的过期时间,平衡安全性和用户体验。
+- **Session ID 安全**:为包含 `SessionID` 的 Cookie 设置 `HttpOnly` 标志可以防止客户端脚本(如 JavaScript)窃取,设置 Secure 标志可以保证 `SessionID` 只在 HTTPS 连接下传输,增加安全性。
+
+Session 数据本身存储在服务器端。常见的存储方式有:
+
+- **服务器内存**:实现简单,访问速度快,但服务器重启数据会丢失,且不利于多服务器间的负载均衡。这种方式适合简单且用户量不大的业务场景。
+- **数据库 (如 MySQL, PostgreSQL)**:数据持久化,但读写性能相对较低,一般不会使用这种方式。
+- **分布式缓存 (如 Redis)**:性能高,支持分布式部署,是目前大规模应用中非常主流的方案。
+
+**方案二:当 Cookie 被禁用时:URL 重写 (URL Rewriting)**
+
+如果用户的浏览器禁用了 Cookie,或者某些情况下不便使用 Cookie,还有一种备选方案是 URL 重写。这种方式会将 `SessionID` 直接附加到 URL 的末尾,作为参数传递。例如:。服务器端会解析 URL 中的 `sessionid` 参数来获取 `SessionID`,进而找到对应的 Session 数据。
+
+这种方法一般不会使用,存在以下缺点:
+
+- URL 会变长且不美观;
+- `SessionID` 暴露在 URL 中,安全性较低(容易被复制、分享或记录在日志中);
+- 对搜索引擎优化 (SEO) 可能不友好。
+
+**方案三:Token-based 认证 (如 JWT - JSON Web Tokens)**
+
+这是一种越来越流行的无状态认证方式,尤其适用于前后端分离的架构和微服务。
+
+
+
+以 JWT 为例(普通 Token 方案也可以),简化后的步骤如下:
+
+1. 用户向服务器发送用户名、密码以及验证码用于登陆系统。
+2. 如果用户名、密码以及验证码校验正确的话,服务端会返回已经签名的 Token,也就是 JWT。
+3. 客户端收到 Token 后自己保存起来(比如浏览器的 `localStorage`)。
+4. 用户以后每次向后端发请求都在 Header 中带上这个 JWT。
+5. 服务端检查 JWT 并从中获取用户相关信息。
+
+JWT 详细介绍可以查看这两篇文章:
+
+- [JWT 基础概念详解](https://javaguide.cn/system-design/security/jwt-intro.html)
+- [JWT 身份认证优缺点分析](https://javaguide.cn/system-design/security/advantages-and-disadvantages-of-jwt.html)
+
+总结来说,虽然 HTTP 本身是无状态的,但通过 Cookie + Session、URL 重写或 Token 等机制,我们能够有效地在 Web 应用中跟踪和管理用户状态。其中,**Cookie + Session 是最传统也最广泛使用的方式,而 Token-based 认证则在现代 Web 应用中越来越受欢迎。**
### URI 和 URL 的区别是什么?
@@ -240,14 +366,12 @@ URI 的作用像身份证号一样,URL 的作用更像家庭住址一样。URL
### Cookie 和 Session 有什么区别?
-准确点来说,这个问题属于认证授权的范畴,你可以在 [认证授权基础概念详解](../../system-design/security/basis-of-authority-certification.md) 这篇文章中找到详细的答案。
+准确点来说,这个问题属于认证授权的范畴,你可以在 [认证授权基础概念详解](https://javaguide.cn/system-design/security/basis-of-authority-certification.html) 这篇文章中找到详细的答案。
-### GET 和 POST 的区别
+### ⭐️GET 和 POST 的区别
这个问题在知乎上被讨论的挺火热的,地址: 。
-
-
GET 和 POST 是 HTTP 协议中两种常用的请求方法,它们在不同的场景和目的下有不同的特点和用法。一般来说,可以从以下几个方面来区分二者(重点搞清两者在语义上的区别即可):
- 语义(主要区别):GET 通常用于获取或查询资源,而 POST 通常用于创建或修改资源。
@@ -279,7 +403,7 @@ WebSocket 协议本质上是应用层的协议,用于弥补 HTTP 协议在持
- 社交聊天
- ……
-### WebSocket 和 HTTP 有什么区别?
+### ⭐️WebSocket 和 HTTP 有什么区别?
WebSocket 和 HTTP 两者都是基于 TCP 的应用层协议,都可以在网络中传输数据。
@@ -295,29 +419,76 @@ WebSocket 和 HTTP 两者都是基于 TCP 的应用层协议,都可以在网
WebSocket 的工作过程可以分为以下几个步骤:
1. 客户端向服务器发送一个 HTTP 请求,请求头中包含 `Upgrade: websocket` 和 `Sec-WebSocket-Key` 等字段,表示要求升级协议为 WebSocket;
-2. 服务器收到这个请求后,会进行升级协议的操作,如果支持 WebSocket,它将回复一个 HTTP 101 状态码,响应头中包含 ,`Connection: Upgrade`和 `Sec-WebSocket-Accept: xxx` 等字段、表示成功升级到 WebSocket 协议。
+2. 服务器收到这个请求后,会进行升级协议的操作,如果支持 WebSocket,它将回复一个 HTTP 101 状态码,响应头中包含 `Connection: Upgrade` 和 `Sec-WebSocket-Accept: xxx` 等字段,表示成功升级到 WebSocket 协议。
3. 客户端和服务器之间建立了一个 WebSocket 连接,可以进行双向的数据传输。数据以帧(frames)的形式进行传送,WebSocket 的每条消息可能会被切分成多个数据帧(最小单位)。发送端会将消息切割成多个帧发送给接收端,接收端接收消息帧,并将关联的帧重新组装成完整的消息。
4. 客户端或服务器可以主动发送一个关闭帧,表示要断开连接。另一方收到后,也会回复一个关闭帧,然后双方关闭 TCP 连接。
另外,建立 WebSocket 连接之后,通过心跳机制来保持 WebSocket 连接的稳定性和活跃性。
-### SSE 与 WebSocket 有什么区别?
+### ⭐️WebSocket 与短轮询、长轮询的区别
+
+这三种方式,都是为了解决“**客户端如何及时获取服务器最新数据,实现实时更新**”的问题。它们的实现方式和效率、实时性差异较大。
+
+**1.短轮询(Short Polling)**
+
+- **原理**:客户端每隔固定时间(如 5 秒)发起一次 HTTP 请求,询问服务器是否有新数据。服务器收到请求后立即响应。
+- **优点**:实现简单,兼容性好,直接用常规 HTTP 请求即可。
+- **缺点**:
+ - **实时性一般**:消息可能在两次轮询间到达,用户需等到下次请求才知晓。
+ - **资源浪费大**:反复建立/关闭连接,且大多数请求收到的都是“无新消息”,极大增加服务器和网络压力。
+
+**2.长轮询(Long Polling)**
+
+- **原理**:客户端发起请求后,若服务器暂时无新数据,则会保持连接,直到有新数据或超时才响应。客户端收到响应后立即发起下一次请求,实现“伪实时”。
+- **优点**:
+ - **实时性较好**:一旦有新数据可立即推送,无需等待下次定时请求。
+ - **空响应减少**:减少了无效的空响应,提升了效率。
+- **缺点**:
+ - **服务器资源占用高**:需长时间维护大量连接,消耗服务器线程/连接数。
+ - **资源浪费大**:每次响应后仍需重新建立连接,且依然基于 HTTP 单向请求-响应机制。
+
+**3. WebSocket**
+
+- **原理**:客户端与服务器通过一次 HTTP Upgrade 握手后,建立一条持久的 TCP 连接。之后,双方可以随时、主动地发送数据,实现真正的全双工、低延迟通信。
+- **优点**:
+ - **实时性强**:数据可即时双向收发,延迟极低。
+ - **资源效率高**:连接持续,无需反复建立/关闭,减少资源消耗。
+ - **功能强大**:支持服务端主动推送消息、客户端主动发起通信。
+- **缺点**:
+ - **使用限制**:需要服务器和客户端都支持 WebSocket 协议。对连接管理有一定要求(如心跳保活、断线重连等)。
+ - **实现麻烦**:实现起来比短轮询和长轮询要更麻烦一些。
+
+
+
+### ⭐️SSE 与 WebSocket 有什么区别?
+
+SSE (Server-Sent Events) 和 WebSocket 都是用来实现服务器向浏览器实时推送消息的技术,让网页内容能自动更新,而不需要用户手动刷新。虽然目标相似,但它们在工作方式和适用场景上有几个关键区别:
-> 摘自[Web 实时消息推送详解](https://javaguide.cn/system-design/web-real-time-message-push.html)。
+1. **通信方式:**
+ - **SSE:** **单向通信**。只有服务器能向客户端(浏览器)发送数据。客户端不能通过同一个连接向服务器发送数据(需要发起新的 HTTP 请求)。
+ - **WebSocket:** **双向通信 (全双工)**。客户端和服务器可以随时互相发送消息,实现真正的实时交互。
+2. **底层协议:**
+ - **SSE:** 基于**标准的 HTTP/HTTPS 协议**。它本质上是一个“长连接”的 HTTP 请求,服务器保持连接打开并持续发送事件流。不需要特殊的服务器或协议支持,现有的 HTTP 基础设施就能用。
+ - **WebSocket:** 使用**独立的 ws:// 或 wss:// 协议**。它需要通过一个特定的 HTTP "Upgrade" 请求来建立连接,并且服务器需要明确支持 WebSocket 协议来处理连接和消息帧。
+3. **实现复杂度和成本:**
+ - **SSE:** **实现相对简单**,主要在服务器端处理。浏览器端有标准的 EventSource API,使用方便。开发和维护成本较低。
+ - **WebSocket:** **稍微复杂一些**。需要服务器端专门处理 WebSocket 连接和协议,客户端也需要使用 WebSocket API。如果需要考虑兼容性、心跳、重连等,开发成本会更高。
+4. **断线重连:**
+ - **SSE:** **浏览器原生支持**。EventSource API 提供了自动断线重连的机制。
+ - **WebSocket:** **需要手动实现**。开发者需要自己编写逻辑来检测断线并进行重连尝试。
+5. **数据类型:**
+ - **SSE:** **主要设计用来传输文本** (UTF-8 编码)。如果需要传输二进制数据,需要先进行 Base64 等编码转换成文本。
+ - **WebSocket:** **原生支持传输文本和二进制数据**,无需额外编码。
-SSE 与 WebSocket 作用相似,都可以建立服务端与浏览器之间的通信,实现服务端向客户端推送消息,但还是有些许不同:
+为了提供更好的用户体验和利用其简单、高效、基于标准 HTTP 的特性,**Server-Sent Events (SSE) 是目前大型语言模型 API(如 OpenAI、DeepSeek 等)实现流式响应的常用甚至可以说是标准的技术选择**。
-- SSE 是基于 HTTP 协议的,它们不需要特殊的协议或服务器实现即可工作;WebSocket 需单独服务器来处理协议。
-- SSE 单向通信,只能由服务端向客户端单向通信;WebSocket 全双工通信,即通信的双方可以同时发送和接受信息。
-- SSE 实现简单开发成本低,无需引入其他组件;WebSocket 传输数据需做二次解析,开发门槛高一些。
-- SSE 默认支持断线重连;WebSocket 则需要自己实现。
-- SSE 只能传送文本消息,二进制数据需要经过编码后传送;WebSocket 默认支持传送二进制数据。
+这里以 DeepSeek 为例,我们发送一个请求并打开浏览器控制台验证一下:
-**SSE 与 WebSocket 该如何选择?**
+
-SSE 好像一直不被大家所熟知,一部分原因是出现了 WebSocket,这个提供了更丰富的协议来执行双向、全双工通信。对于游戏、即时通信以及需要双向近乎实时更新的场景,拥有双向通道更具吸引力。
+
-但是,在某些情况下,不需要从客户端发送数据。而你只需要一些服务器操作的更新。比如:站内信、未读消息数、状态更新、股票行情、监控数量等场景,SEE 不管是从实现的难易和成本上都更加有优势。此外,SSE 具有 WebSocket 在设计上缺乏的多种功能,例如:自动重新连接、事件 ID 和发送任意事件的能力。
+可以看到,响应头里包含了 `text/event-stream`,说明使用的确实是 SSE。并且,响应数据也确实是持续分块传输。
## PING
@@ -386,15 +557,15 @@ DNS 服务器自底向上可以依次分为以下几个层级(所有 DNS 服务
- 权威 DNS 服务器。在因特网上具有公共可访问主机的每个组织机构必须提供公共可访问的 DNS 记录,这些记录将这些主机的名字映射为 IP 地址。
- 本地 DNS 服务器。每个 ISP(互联网服务提供商)都有一个自己的本地 DNS 服务器。当主机发出 DNS 请求时,该请求被发往本地 DNS 服务器,它起着代理的作用,并将该请求转发到 DNS 层次结构中。严格说来,不属于 DNS 层级结构
-世界上并不是只有 13 台根服务器,这是很多人普遍的误解,网上很多文章也是这么写的。实际上,现在根服务器数量远远超过这个数量。最初确实是为 DNS 根服务器分配了 13 个 IP 地址,每个 IP 地址对应一个不同的根 DNS 服务器。然而,由于互联网的快速发展和增长,这个原始的架构变得不太适应当前的需求。为了提高 DNS 的可靠性、安全性和性能,目前这 13 个 IP 地址中的每一个都有多个服务器,截止到 2023 年底,所有根服务器之和达到了 600 多台,未来还会继续增加。
+世界上并不是只有 13 台根服务器,这是很多人普遍的误解,网上很多文章也是这么写的。实际上,现在根服务器数量远远超过这个数量。最初确实是为 DNS 根服务器分配了 13 个 IP 地址,每个 IP 地址对应一个不同的根 DNS 服务器。然而,由于互联网的快速发展和增长,这个原始的架构变得不太适应当前的需求。为了提高 DNS 的可靠性、安全性和性能,目前这 13 个 IP 地址中的每一个都有多个服务器,截止到 2023 年底,所有根服务器之和达到了 1700 多台,未来还会继续增加。
-### DNS 解析的过程是什么样的?
+### ⭐️DNS 解析的过程是什么样的?
-整个过程的步骤比较多,我单独写了一篇文章详细介绍:[DNS 域名系统详解(应用层)](./dns.md) 。
+整个过程的步骤比较多,我单独写了一篇文章详细介绍:[DNS 域名系统详解(应用层)](https://javaguide.cn/cs-basics/network/dns.html) 。
### DNS 劫持了解吗?如何应对?
-DNS 劫持是一种网络攻击,它通过修改 DNS 服务器的解析结果,使用户访问的域名指向错误的 IP 地址,从而导致用户无法访问正常的网站,或者被引导到恶意的网站。DNS 劫持有时也被称为 DNS 重定向、DNS 欺骗或 DNS 污染。DNS 劫持详细介绍可以参考:[黑客技术?没你想象的那么难!——DNS 劫持篇](https://cloud.tencent.com/developer/article/1197474)。
+DNS 劫持是一种网络攻击,它通过修改 DNS 服务器的解析结果,使用户访问的域名指向错误的 IP 地址,从而导致用户无法访问正常的网站,或者被引导到恶意的网站。DNS 劫持有时也被称为 DNS 重定向、DNS 欺骗或 DNS 污染。
## 参考
diff --git a/docs/cs-basics/network/other-network-questions2.md b/docs/cs-basics/network/other-network-questions2.md
index d5054865497..86bda330efa 100644
--- a/docs/cs-basics/network/other-network-questions2.md
+++ b/docs/cs-basics/network/other-network-questions2.md
@@ -1,41 +1,78 @@
---
title: 计算机网络常见面试题总结(下)
+description: 最新计算机网络高频面试题总结(下):TCP/UDP深度对比、三次握手四次挥手、HTTP/3 QUIC优化、IPv6优势、NAT/ARP详解,附表格+⭐️重点标注,一文掌握传输层&网络层核心考点,快速通关后端技术面试!
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: 计算机网络面试题,TCP vs UDP,TCP三次握手,HTTP/3 QUIC,IPv4 vs IPv6,TCP可靠性,IP地址,NAT协议,ARP协议,传输层面试,网络层高频题,基于TCP协议,基于UDP协议,队头阻塞,四次挥手
---
-下篇主要是传输层和网络层相关的内容。
+计算机网络面试题里,真正容易被追问到细节的部分,往往集中在 **TCP、UDP、IP、ARP、NAT、IPv4/IPv6** 这些传输层和网络层知识点上。比如:为什么 TCP 可靠?为什么要三次握手和四次挥手?HTTP/3 为什么改用基于 UDP 的 QUIC?这些问题不仅考概念,也考你对网络通信过程的理解。
-## TCP 与 UDP
+这篇《计算机网络常见面试题总结(下)》会重点梳理 TCP 与 UDP、TCP 连接管理、可靠传输、IP 地址、ARP、NAT 等后端面试高频内容,帮助你把传输层和网络层的核心考点串起来。
-### TCP 与 UDP 的区别(重要)
+## TCP 与 UDP
-1. **是否面向连接**:UDP 在传送数据之前不需要先建立连接。而 TCP 提供面向连接的服务,在传送数据之前必须先建立连接,数据传送结束后要释放连接。
-2. **是否是可靠传输**:远地主机在收到 UDP 报文后,不需要给出任何确认,并且不保证数据不丢失,不保证是否顺序到达。TCP 提供可靠的传输服务,TCP 在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制。通过 TCP 连接传输的数据,无差错、不丢失、不重复、并且按序到达。
-3. **是否有状态**:这个和上面的“是否可靠传输”相对应。TCP 传输是有状态的,这个有状态说的是 TCP 会去记录自己发送消息的状态比如消息是否发送了、是否被接收了等等。为此 ,TCP 需要维持复杂的连接状态表。而 UDP 是无状态服务,简单来说就是不管发出去之后的事情了(**这很渣男!**)。
-4. **传输效率**:由于使用 TCP 进行传输的时候多了连接、确认、重传等机制,所以 TCP 的传输效率要比 UDP 低很多。
-5. **传输形式**:TCP 是面向字节流的,UDP 是面向报文的。
-6. **首部开销**:TCP 首部开销(20 ~ 60 字节)比 UDP 首部开销(8 字节)要大。
-7. **是否提供广播或多播服务**:TCP 只支持点对点通信,UDP 支持一对一、一对多、多对一、多对多;
+### ⭐️TCP 与 UDP 的区别(重要)
+
+1. **是否面向连接**:
+ - TCP 是面向连接的。在传输数据之前,必须先通过“三次握手”建立连接;数据传输完成后,还需要通过“四次挥手”来释放连接。这保证了双方都准备好通信。
+ - UDP 是无连接的。发送数据前不需要建立任何连接,直接把数据包(数据报)扔出去。
+2. **是否是可靠传输**:
+ - TCP 提供可靠的数据传输服务。它通过序列号、确认应答 (ACK)、超时重传、流量控制、拥塞控制等一系列机制,来确保数据能够无差错、不丢失、不重复且按顺序地到达目的地。
+ - UDP 提供不可靠的传输。它尽最大努力交付 (best-effort delivery),但不保证数据一定能到达,也不保证到达的顺序,更不会自动重传。收到报文后,接收方也不会主动发确认。
+3. **是否有状态**:
+ - TCP 是有状态的。因为要保证可靠性,TCP 需要在连接的两端维护连接状态信息,比如序列号、窗口大小、哪些数据发出去了、哪些收到了确认等。
+ - UDP 是无状态的。它不维护连接状态,发送方发出数据后就不再关心它是否到达以及如何到达,因此开销更小(**这很“渣男”!**)。
+4. **传输效率**:
+ - TCP 因为需要建立连接、发送确认、处理重传等,其开销较大,传输效率相对较低。
+ - UDP 结构简单,没有复杂的控制机制,开销小,传输效率更高,速度更快。
+5. **传输形式**:
+ - TCP 是面向字节流 (Byte Stream) 的。它将应用程序交付的数据视为一连串无结构的字节流,可能会对数据进行拆分或合并。
+ - UDP 是面向报文 (Message Oriented) 的。应用程序交给 UDP 多大的数据块,UDP 就照样发送,既不拆分也不合并,保留了应用程序消息的边界。
+6. **首部开销**:
+ - TCP 的头部至少需要 20 字节,如果包含选项字段,最多可达 60 字节。
+ - UDP 的头部非常简单,固定只有 8 字节。
+7. **是否提供广播或多播服务**:
+ - TCP 只支持点对点 (Point-to-Point) 的单播通信。
+ - UDP 支持一对一 (单播)、一对多 (多播/Multicast) 和一对所有 (广播/Broadcast) 的通信方式。
8. ……
-我把上面总结的内容通过表格形式展示出来了!确定不点个赞嘛?
+为了更直观地对比,可以看下面这个表格:
+
+| 特性 | TCP | UDP |
+| ------------ | -------------------------- | ----------------------------------- |
+| **连接性** | 面向连接 | 无连接 |
+| **可靠性** | 可靠 | 不可靠 (尽力而为) |
+| **状态维护** | 有状态 | 无状态 |
+| **传输效率** | 较低 | 较高 |
+| **传输形式** | 面向字节流 | 面向数据报 (报文) |
+| **头部开销** | 20 - 60 字节 | 8 字节 |
+| **通信模式** | 点对点 (单播) | 单播、多播、广播 |
+| **常见应用** | HTTP/HTTPS, FTP, SMTP, SSH | DNS, DHCP, SNMP, TFTP, VoIP, 视频流 |
+
+### ⭐️什么时候选择 TCP,什么时候选 UDP?
-| | TCP | UDP |
-| ---------------------- | -------------- | ---------- |
-| 是否面向连接 | 是 | 否 |
-| 是否可靠 | 是 | 否 |
-| 是否有状态 | 是 | 否 |
-| 传输效率 | 较慢 | 较快 |
-| 传输形式 | 字节流 | 数据报文段 |
-| 首部开销 | 20 ~ 60 bytes | 8 bytes |
-| 是否提供广播或多播服务 | 否 | 是 |
+选择 TCP 还是 UDP,主要取决于你的应用**对数据传输的可靠性要求有多高,以及对实时性和效率的要求有多高**。
-### 什么时候选择 TCP,什么时候选 UDP?
+当**数据准确性和完整性至关重要,一点都不能出错**时,通常选择 TCP。因为 TCP 提供了一整套机制(三次握手、确认应答、重传、流量控制等)来保证数据能够可靠、有序地送达。典型应用场景如下:
-- **UDP 一般用于即时通信**,比如:语音、 视频、直播等等。这些场景对传输数据的准确性要求不是特别高,比如你看视频即使少个一两帧,实际给人的感觉区别也不大。
-- **TCP 用于对传输准确性要求特别高的场景**,比如文件传输、发送和接收邮件、远程登录等等。
+- **Web 浏览 (HTTP/HTTPS):** 网页内容、图片、脚本必须完整加载才能正确显示。
+- **文件传输 (FTP, SCP):** 文件内容不允许有任何字节丢失或错序。
+- **邮件收发 (SMTP, POP3, IMAP):** 邮件内容需要完整无误地送达。
+- **远程登录 (SSH, Telnet):** 命令和响应需要准确传输。
+- ……
+
+当**实时性、速度和效率优先,并且应用能容忍少量数据丢失或乱序**时,通常选择 UDP。UDP 开销小、传输快,没有建立连接和保证可靠性的复杂过程。典型应用场景如下:
+
+- **实时音视频通信 (VoIP, 视频会议, 直播):** 偶尔丢失一两个数据包(可能导致画面或声音短暂卡顿)通常比因为等待重传(TCP 机制)导致长时间延迟更可接受。应用层可能会有自己的补偿机制。
+- **在线游戏:** 需要快速传输玩家位置、状态等信息,对实时性要求极高,旧的数据很快就没用了,丢失少量数据影响通常不大。
+- **DHCP (动态主机配置协议):** 客户端在请求 IP 时自身没有 IP 地址,无法满足 TCP 建立连接的前提条件,并且 DHCP 有广播需求、交互模式简单以及自带可靠性机制。
+- **物联网 (IoT) 数据上报:** 某些场景下,传感器定期上报数据,丢失个别数据点可能不影响整体趋势分析。
+- ……
### HTTP 基于 TCP 还是 UDP?
@@ -43,9 +80,21 @@ tag:
🐛 修正(参见 [issue#1915](https://github.com/Snailclimb/JavaGuide/issues/1915)):
-HTTP/3.0 之前是基于 TCP 协议的,而 HTTP/3.0 将弃用 TCP,改用 **基于 UDP 的 QUIC 协议** 。
+HTTP/3.0 之前是基于 TCP 协议的,而 HTTP/3.0 将弃用 TCP,改用 **基于 UDP 的 QUIC 协议** :
-此变化解决了 HTTP/2 中存在的队头阻塞问题。队头阻塞是指在 HTTP/2.0 中,多个 HTTP 请求和响应共享一个 TCP 连接,如果其中一个请求或响应因为网络拥塞或丢包而被阻塞,那么后续的请求或响应也无法发送,导致整个连接的效率降低。这是由于 HTTP/2.0 在单个 TCP 连接上使用了多路复用,受到 TCP 拥塞控制的影响,少量的丢包就可能导致整个 TCP 连接上的所有流被阻塞。HTTP/3.0 在一定程度上解决了队头阻塞问题,一个连接建立多个不同的数据流,这些数据流之间独立互不影响,某个数据流发生丢包了,其数据流不受影响(本质上是多路复用+轮询)。
+- **HTTP/1.x 和 HTTP/2.0**:这两个版本的 HTTP 协议都明确建立在 TCP 之上。TCP 提供了可靠的、面向连接的传输,确保数据按序、无差错地到达,这对于网页内容的正确展示非常重要。发送 HTTP 请求前,需要先通过 TCP 的三次握手建立连接。
+- **HTTP/3.0**:这是一个重大的改变。HTTP/3 弃用了 TCP,转而使用 QUIC 协议,而 QUIC 是构建在 UDP 之上的。
+
+
+
+**为什么 HTTP/3 要做这个改变呢?主要有两大原因:**
+
+1. 解决队头阻塞 (Head-of-Line Blocking,简写:HOL blocking) 问题。
+2. 减少连接建立的延迟。
+
+下面我们来详细介绍这两大优化。
+
+在 HTTP/2 中,虽然可以在一个 TCP 连接上并发传输多个请求/响应流(多路复用),但 TCP 本身的特性(保证有序、可靠)意味着如果其中一个流的某个 TCP 报文丢失或延迟,整个 TCP 连接都会被阻塞,等待该报文重传。这会导致所有在这个 TCP 连接上的 HTTP/2 流都受到影响,即使其他流的数据包已经到达。**QUIC (运行在 UDP 上) 解决了这个问题**。QUIC 内部实现了自己的多路复用和流控制机制。不同的 HTTP 请求/响应流在 QUIC 层面是真正独立的。如果一个流的数据包丢失,它只会阻塞该流,而不会影响同一 QUIC 连接上的其他流(本质上是多路复用+轮询),大大提高了并发传输的效率。
除了解决队头阻塞问题,HTTP/3.0 还可以减少握手过程的延迟。在 HTTP/2.0 中,如果要建立一个安全的 HTTPS 连接,需要经过 TCP 三次握手和 TLS 握手:
@@ -59,27 +108,57 @@ HTTP/3.0 之前是基于 TCP 协议的,而 HTTP/3.0 将弃用 TCP,改用 **
-
-
-### 使用 TCP 的协议有哪些?使用 UDP 的协议有哪些?
+### 为什么 TCP 是面向字节流,UDP 是面向报文?
-**运行于 TCP 协议之上的协议**:
+
-1. **HTTP 协议(HTTP/3.0 之前)**:超文本传输协议(HTTP,HyperText Transfer Protocol)是一种用于传输超文本和多媒体内容的协议,主要是为 Web 浏览器与 Web 服务器之间的通信而设计的。当我们使用浏览器浏览网页的时候,我们网页就是通过 HTTP 请求进行加载的。
-2. **HTTPS 协议**:更安全的超文本传输协议(HTTPS,Hypertext Transfer Protocol Secure),身披 SSL 外衣的 HTTP 协议
-3. **FTP 协议**:文件传输协议 FTP(File Transfer Protocol)是一种用于在计算机之间传输文件的协议,可以屏蔽操作系统和文件存储方式。注意 ⚠️:FTP 是一种不安全的协议,因为它在传输过程中不会对数据进行加密。建议在传输敏感数据时使用更安全的协议,如 SFTP。
-4. **SMTP 协议**:简单邮件传输协议(SMTP,Simple Mail Transfer Protocol)的缩写,是一种用于发送电子邮件的协议。注意 ⚠️:SMTP 协议只负责邮件的发送,而不是接收。要从邮件服务器接收邮件,需要使用 POP3 或 IMAP 协议。
-5. **POP3/IMAP 协议**:两者都是负责邮件接收的协议。IMAP 协议是比 POP3 更新的协议,它在功能和性能上都更加强大。IMAP 支持邮件搜索、标记、分类、归档等高级功能,而且可以在多个设备之间同步邮件状态。几乎所有现代电子邮件客户端和服务器都支持 IMAP。
-6. **Telnet 协议**:用于通过一个终端登陆到其他服务器。Telnet 协议的最大缺点之一是所有数据(包括用户名和密码)均以明文形式发送,这有潜在的安全风险。这就是为什么如今很少使用 Telnet,而是使用一种称为 SSH 的非常安全的网络传输协议的主要原因。
-7. **SSH 协议** : SSH( Secure Shell)是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。SSH 建立在可靠的传输协议 TCP 之上。
-8. ……
+TCP 是面向字节流的。应用层写入的数据会进入内核缓冲区,TCP 只保证这些字节可靠、有序地到达对端,不保证一次 `send()` 对应一次 `recv()`,也不保留应用层消息边界。因此接收方可能一次读到多条消息,也可能只读到半条消息,这就是常说的粘包、拆包现象。
+
+
+UDP 是面向报文的。应用层交给 UDP 的一次数据会作为一个 UDP 数据报发送,接收端也是按数据报读取,所以天然保留消息边界。不过 UDP 不保证可靠到达,也不保证顺序。
-**运行于 UDP 协议之上的协议**:
+解决 TCP 粘包/拆包,本质是应用层协议自己定义消息边界。常见方案有固定长度、分隔符、长度头。工程里更常用长度头,因为它对二进制协议和变长消息更友好,但要处理字节序、最大长度限制、半包缓存和异常连接关闭等问题。
-1. **HTTP 协议(HTTP/3.0 )**: HTTP/3.0 弃用 TCP,改用基于 UDP 的 QUIC 协议 。
-2. **DHCP 协议**:动态主机配置协议,动态配置 IP 地址
-3. **DNS**:域名系统(DNS,Domain Name System)将人类可读的域名 (例如,www.baidu.com) 转换为机器可读的 IP 地址 (例如,220.181.38.148)。 我们可以将其理解为专为互联网设计的电话薄。实际上,DNS 同时支持 UDP 和 TCP 协议。
-4. ……
+
-### TCP 三次握手和四次挥手(非常重要)
+详细介绍:[为什么 TCP 是面向字节流,UDP 是面向报文?](./tcp-byte-stream-udp-datagram.md)
+
+### 你知道哪些基于 TCP/UDP 的协议?
+
+TCP (传输控制协议) 和 UDP (用户数据报协议) 是互联网传输层的两大核心协议,它们为各种应用层协议提供了基础的通信服务。以下是一些常见的、分别构建在 TCP 和 UDP 之上的应用层协议:
+
+**运行于 TCP 协议之上的协议 (强调可靠、有序传输):**
+
+| 中文全称 (缩写) | 英文全称 | 主要用途 | 说明与特性 |
+| -------------------------- | ---------------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
+| 超文本传输协议 (HTTP) | HyperText Transfer Protocol | 传输网页、超文本、多媒体内容 | **HTTP/1.x 和 HTTP/2 基于 TCP**。早期版本不加密,是 Web 通信的基础。 |
+| 安全超文本传输协议 (HTTPS) | HyperText Transfer Protocol Secure | 加密的网页传输 | 在 HTTP 和 TCP 之间增加了 SSL/TLS 加密层,确保数据传输的机密性和完整性。 |
+| 文件传输协议 (FTP) | File Transfer Protocol | 文件传输 | 传统的 FTP **明文传输**,不安全。推荐使用其安全版本 **SFTP (SSH File Transfer Protocol)** 或 **FTPS (FTP over SSL/TLS)** 。 |
+| 简单邮件传输协议 (SMTP) | Simple Mail Transfer Protocol | **发送**电子邮件 | 负责将邮件从客户端发送到服务器,或在邮件服务器之间传递。可通过 **STARTTLS** 升级到加密传输。 |
+| 邮局协议第 3 版 (POP3) | Post Office Protocol version 3 | **接收**电子邮件 | 通常将邮件从服务器**下载到本地设备后删除服务器副本** (可配置保留)。**POP3S** 是其 SSL/TLS 加密版本。 |
+| 互联网消息访问协议 (IMAP) | Internet Message Access Protocol | **接收和管理**电子邮件 | 邮件保留在服务器,支持多设备同步邮件状态、文件夹管理、在线搜索等。**IMAPS** 是其 SSL/TLS 加密版本。现代邮件服务首选。 |
+| 远程终端协议 (Telnet) | Teletype Network | 远程终端登录 | **明文传输**所有数据 (包括密码),安全性极差,基本已被 SSH 完全替代。 |
+| 安全外壳协议 (SSH) | Secure Shell | 安全远程管理、加密数据传输 | 提供了加密的远程登录和命令执行,以及安全的文件传输 (SFTP) 等功能,是 Telnet 的安全替代品。 |
+
+**运行于 UDP 协议之上的协议 (强调快速、低开销传输):**
+
+| 中文全称 (缩写) | 英文全称 | 主要用途 | 说明与特性 |
+| ----------------------- | ------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------ |
+| 超文本传输协议 (HTTP/3) | HyperText Transfer Protocol version 3 | 新一代网页传输 | 基于 **QUIC** 协议 (QUIC 本身构建于 UDP 之上),旨在减少延迟、解决 TCP 队头阻塞问题,支持 0-RTT 连接建立。 |
+| 动态主机配置协议 (DHCP) | Dynamic Host Configuration Protocol | 动态分配 IP 地址及网络配置 | 客户端从服务器自动获取 IP 地址、子网掩码、网关、DNS 服务器等信息。 |
+| 域名系统 (DNS) | Domain Name System | 域名到 IP 地址的解析 | **通常使用 UDP** 进行快速查询。当响应数据包过大或进行区域传送 (AXFR) 时,会**切换到 TCP** 以保证数据完整性。 |
+| 实时传输协议 (RTP) | Real-time Transport Protocol | 实时音视频数据流传输 | 常用于 VoIP、视频会议、直播等。追求低延迟,允许少量丢包。通常与 RTCP 配合使用。 |
+| RTP 控制协议 (RTCP) | RTP Control Protocol | RTP 流的质量监控和控制信息 | 配合 RTP 工作,提供丢包、延迟、抖动等统计信息,辅助流量控制和拥塞管理。 |
+| 简单文件传输协议 (TFTP) | Trivial File Transfer Protocol | 简化的文件传输 | 功能简单,常用于局域网内无盘工作站启动、网络设备固件升级等小文件传输场景。 |
+| 简单网络管理协议 (SNMP) | Simple Network Management Protocol | 网络设备的监控与管理 | 允许网络管理员查询和修改网络设备的状态信息。 |
+| 网络时间协议 (NTP) | Network Time Protocol | 同步计算机时钟 | 用于在网络中的计算机之间同步时间,确保时间的一致性。 |
+
+**总结一下:**
+
+- **TCP** 更适合那些对数据**可靠性、完整性和顺序性**要求高的应用,如网页浏览 (HTTP/HTTPS)、文件传输 (FTP/SFTP)、邮件收发 (SMTP/POP3/IMAP)。
+- **UDP** 则更适用于那些对**实时性要求高、能容忍少量数据丢失**的应用,如域名解析 (DNS)、实时音视频 (RTP)、在线游戏、网络管理 (SNMP) 等。
+
+### ⭐️TCP 三次握手和四次挥手(非常重要)
**相关面试题**:
@@ -90,11 +169,22 @@ HTTP/3.0 之前是基于 TCP 协议的,而 HTTP/3.0 将弃用 TCP,改用 **
- 如果第二次挥手时服务器的 ACK 没有送达客户端,会怎样?
- 为什么第四次挥手客户端需要等待 2\*MSL(报文段最长寿命)时间后才进入 CLOSED 状态?
-**参考答案**:[TCP 三次握手和四次挥手(传输层)](./tcp-connection-and-disconnection.md) 。
+**参考答案**:[TCP 三次握手和四次挥手(传输层)](https://javaguide.cn/cs-basics/network/tcp-connection-and-disconnection.html) 。
+
+### TIME_WAIT
+
+**相关面试题**:
+
+1. `TIME_WAIT` 到底在等什么?
+2. `TIME_WAIT` 大量堆积会不会真的出问题?
+3. `tcp_tw_reuse` 能不能随便开?
+4. `TIME_WAIT` 和 `CLOSE_WAIT` 怎么区分?
+
+**参考答案**: [TCP TIME_WAIT 详解:为什么要等、会不会出问题、能不能复用?](./tcp-time-wait.md)。
-### TCP 如何保证传输的可靠性?(重要)
+### ⭐️TCP 如何保证传输的可靠性?(重要)
-[TCP 传输可靠性保障(传输层)](./tcp-reliability-guarantee.md)
+[TCP 传输可靠性保障(传输层)](https://javaguide.cn/cs-basics/network/tcp-reliability-guarantee.html)
## IP
@@ -122,7 +212,7 @@ HTTP/3.0 之前是基于 TCP 协议的,而 HTTP/3.0 将弃用 TCP,改用 **
IP 地址过滤是一种简单的网络安全措施,实际应用中一般会结合其他网络安全措施,如认证、授权、加密等一起使用。单独使用 IP 地址过滤并不能完全保证网络的安全。
-### IPv4 和 IPv6 有什么区别?
+### ⭐️IPv4 和 IPv6 有什么区别?
**IPv4(Internet Protocol version 4)** 是目前广泛使用的 IP 地址版本,其格式是四组由点分隔的数字,例如:123.89.46.72。IPv4 使用 32 位地址作为其 Internet 地址,这意味着共有约 42 亿( 2^32)个可用 IP 地址。
@@ -145,7 +235,7 @@ IP 地址过滤是一种简单的网络安全措施,实际应用中一般会
获取客户端真实 IP 的方法有多种,主要分为应用层方法、传输层方法和网络层方法。
-**应用层方法** :
+**应用层方法**:
通过 [X-Forwarded-For](https://en.wikipedia.org/wiki/X-Forwarded-For) 请求头获取,简单方便。不过,这种方法无法保证获取到的是真实 IP,这是因为 X-Forwarded-For 字段可能会被伪造。如果经过多个代理服务器,X-Forwarded-For 字段可能会有多个值(附带了整个请求链中的所有代理服务器 IP 地址)。并且,这种方法只适用于 HTTP 和 SMTP 协议。
@@ -157,7 +247,7 @@ IP 地址过滤是一种简单的网络安全措施,实际应用中一般会
**网络层方法**:
-隧道 +DSR 模式。这种方法可以适用于任何协议,就是实施起来会比较麻烦,也存在一定限制,实际应用中一般不会使用这种方法。
+隧道 + DSR 模式。这种方法可以适用于任何协议,就是实施起来会比较麻烦,也存在一定限制,实际应用中一般不会使用这种方法。
### NAT 的作用是什么?
@@ -167,7 +257,7 @@ NAT 不光可以缓解 IPv4 地址资源短缺的问题,还可以隐藏内部

-相关阅读:[NAT 协议详解(网络层)](./nat.md)。
+相关阅读:[NAT 协议详解(网络层)](https://javaguide.cn/cs-basics/network/nat.html)。
## ARP
@@ -175,25 +265,25 @@ NAT 不光可以缓解 IPv4 地址资源短缺的问题,还可以隐藏内部
MAC 地址的全称是 **媒体访问控制地址(Media Access Control Address)**。如果说,互联网中每一个资源都由 IP 地址唯一标识(IP 协议内容),那么一切网络设备都由 MAC 地址唯一标识。
-
+
可以理解为,MAC 地址是一个网络设备真正的身份证号,IP 地址只是一种不重复的定位方式(比如说住在某省某市某街道的张三,这种逻辑定位是 IP 地址,他的身份证号才是他的 MAC 地址),也可以理解为 MAC 地址是身份证号,IP 地址是邮政地址。MAC 地址也有一些别称,如 LAN 地址、物理地址、以太网地址等。
> 还有一点要知道的是,不仅仅是网络资源才有 IP 地址,网络设备也有 IP 地址,比如路由器。但从结构上说,路由器等网络设备的作用是组成一个网络,而且通常是内网,所以它们使用的 IP 地址通常是内网 IP,内网的设备在与内网以外的设备进行通信时,需要用到 NAT 协议。
-MAC 地址的长度为 6 字节(48 比特),地址空间大小有 280 万亿之多($2^{48}$),MAC 地址由 IEEE 统一管理与分配,理论上,一个网络设备中的网卡上的 MAC 地址是永久的。不同的网卡生产商从 IEEE 那里购买自己的 MAC 地址空间(MAC 的前 24 比特),也就是前 24 比特由 IEEE 统一管理,保证不会重复。而后 24 比特,由各家生产商自己管理,同样保证生产的两块网卡的 MAC 地址不会重复。
+MAC 地址的长度为 6 字节(48 比特),地址空间大小有 280 万亿之多( $2^{48}$ ),MAC 地址由 IEEE 统一管理与分配,理论上,一个网络设备中的网卡上的 MAC 地址是永久的。不同的网卡生产商从 IEEE 那里购买自己的 MAC 地址空间(MAC 的前 24 比特),也就是前 24 比特由 IEEE 统一管理,保证不会重复。而后 24 比特,由各家生产商自己管理,同样保证生产的两块网卡的 MAC 地址不会重复。
MAC 地址具有可携带性、永久性,身份证号永久地标识一个人的身份,不论他到哪里都不会改变。而 IP 地址不具有这些性质,当一台设备更换了网络,它的 IP 地址也就可能发生改变,也就是它在互联网中的定位发生了变化。
最后,记住,MAC 地址有一个特殊地址:FF-FF-FF-FF-FF-FF(全 1 地址),该地址表示广播地址。
-### ARP 协议解决了什么问题?
+### ⭐️ARP 协议解决了什么问题?
ARP 协议,全称 **地址解析协议(Address Resolution Protocol)**,它解决的是网络层地址和链路层地址之间的转换问题。因为一个 IP 数据报在物理上传输的过程中,总是需要知道下一跳(物理上的下一个目的地)该去往何处,但 IP 地址属于逻辑地址,而 MAC 地址才是物理地址,ARP 协议解决了 IP 地址转 MAC 地址的一些问题。
### ARP 协议的工作原理?
-[ARP 协议详解(网络层)](./arp.md)
+[ARP 协议详解(网络层)](https://javaguide.cn/cs-basics/network/arp.html)
## 复习建议
diff --git a/docs/cs-basics/network/tcp-byte-stream-udp-datagram.md b/docs/cs-basics/network/tcp-byte-stream-udp-datagram.md
new file mode 100644
index 00000000000..f19ef68b3dd
--- /dev/null
+++ b/docs/cs-basics/network/tcp-byte-stream-udp-datagram.md
@@ -0,0 +1,164 @@
+---
+title: 为什么 TCP 是面向字节流,UDP 是面向报文?(传输层)
+description: 讲清 TCP 字节流与 UDP 报文的本质差异,解析粘包/拆包成因与解决方案,覆盖 Nagle、Delayed ACK 等常见面试考点。
+category: 计算机基础
+tag:
+ - 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: TCP,UDP,字节流,报文,粘包,拆包,消息边界,Nagle,Delayed ACK,TCP_NODELAY
+---
+
+前面说 TCP 是面向字节流,UDP 是面向报文。这个点看起来像一句定义,但很多粘包、拆包问题,其实都藏在这里。
+
+先说结论:**TCP 只保证字节可靠、有序地到达,不保证应用层消息边界;UDP 会保留应用层交给它的报文边界。**
+
+这篇文章主要回答几个问题:
+
+1. 为什么说 TCP 是面向字节流,UDP 是面向报文?
+2. TCP 粘包、拆包到底是怎么产生的?
+3. 应用层应该如何定义消息边界?
+4. Nagle 算法和 Delayed ACK 为什么可能让小包变慢?
+
+举个例子,应用层连续发送两条消息:
+
+```
+消息 1:hello
+消息 2:world
+```
+
+如果用 UDP 发送,通常会对应两个 UDP 数据报。接收方调用 `recvfrom()` 时,也是按数据报来读:一次读取一个 UDP 报文,不会把两次发送的报文合成一个流。UDP 的接收队列里,一个元素就是一个数据报,消息边界天然保留了下来。
+
+不过这里也有一个细节:UDP 保留的是传输层报文边界,不代表它适合发送任意大的消息。数据报太大时,底层 IP 层仍可能分片;接收端缓冲区太小时,也可能出现截断。所以 UDP 的“面向报文”不是“随便发多大都没事”,而是说它不会像 TCP 那样把应用数据抽象成一条连续字节流。RFC 768 对 UDP 的定义就是 datagram mode,并说明它提供的是最小协议机制,不保证可靠交付和去重。
+
+如果用 TCP 发送,就不能这么理解。应用层调用两次 `send()`,只是把两段字节写进内核发送缓冲区。至于这些字节什么时候发、合成几个 TCP 段发、对端一次 `recv()` 能读到多少,都不是由这两次 `send()` 直接决定的。
+
+比如,接收端可能一次读到(粘包):
+
+```
+helloworld
+```
+
+也可能分几次读到(拆包):
+
+```
+hel
+lowor
+ld
+```
+
+这不是 TCP 出错,而是 TCP 的工作方式本来就是这样。TCP 处理的是连续字节流,它只关心这些字节是否可靠、有序地到达,不关心应用层定义的“第几条消息”从哪里开始、到哪里结束。RFC 9293 也明确提到,TCP segment 和应用层 `send()` / socket write 的边界通常不是一一对应的,TCP 不保证应用读写缓冲区边界和网络分段边界相关。
+
+
+
+所以,“TCP 粘包/拆包”这个说法更像是应用层视角下的现象。严格来说,TCP 没有“包”的概念,它传的是连续字节流。真正需要解决的是:**应用层协议如何定义消息边界**。
+
+#### 为什么会出现粘包和拆包?
+
+常见原因有这几个。
+
+**1. TCP 是字节流协议,没有应用层消息边界。**
+
+TCP 负责把字节可靠、有序地送到对端,但不会记录“这 20 个字节是第一条消息,那 30 个字节是第二条消息”。
+
+**2. 一次 `send()` 不等于一次网络发送。**
+
+`send()` 成功通常只表示数据从应用进程拷贝到了内核发送缓冲区。至于什么时候真正发出去、拆成几个 TCP 段发,要看 MSS、发送窗口、拥塞窗口、Nagle 算法、网卡队列等因素。
+
+**3. 一次 `recv()` 也不等于读到一条完整消息。**
+
+接收端只是从 TCP 接收缓冲区取字节。缓冲区里可能已经堆了多条消息,也可能只有半条消息。`recv()` 只会把当前可读的数据拷贝给应用,不会帮你按业务消息切分。
+
+**4. 小包优化可能改变发送时机。**
+
+Nagle 算法、Delayed ACK、Linux 自动合并小写入等机制,都可能影响小数据的发送时机。比如 Linux 从 3.14 开始有 `tcp_autocorking`,内核会尽量合并连续的小写入,减少发送包数量;应用也可以用 `TCP_CORK` 明确控制何时“拔塞”发送。
+
+这也是为什么在 Netty、Dubbo、自定义 RPC、IM 网关、游戏服务里,协议编解码都很重要。只要底层用的是 TCP,就必须在应用层定义清楚消息边界。
+
+
+
+#### 怎么解决 TCP 粘包/拆包?
+
+核心思路只有一个:**让接收方知道一条消息到哪里结束。**
+
+
+
+常见做法有三种。
+
+**1. 固定长度**
+
+规定每条消息都是固定长度,比如 64 字节。接收方每读满 64 字节,就认为读到了一条完整消息。
+
+这种方式实现简单,但灵活性差。消息短了要补齐,浪费空间;消息长了又要额外拆分。它适合消息格式非常固定的场景,不太适合通用业务协议。
+
+**2. 分隔符**
+
+在消息之间加特殊分隔符,比如换行符 `\n`、`\r\n`,或者自定义结束标记。
+
+```
+hello\n
+world\n
+```
+
+接收方不断从缓冲区读数据,只要遇到分隔符,就切出一条完整消息。很多文本协议都会用类似思路。
+
+这种方式直观,但要注意两个问题:第一,分隔符可能刚好出现在消息体里,这时需要转义;第二,分隔符本身也可能被拆在两次读取里,所以接收端解析时不能假设一次 `recv()` 就能读到完整分隔符。
+
+**3. 长度头**
+
+这是工程里更常见的一种方式。协议头里固定放一个长度字段,表示后面的消息体有多少字节。
+
+```
+| 4 字节长度 | 消息体 |
+```
+
+接收方先读固定长度的协议头,解析出消息体长度,再继续读取指定字节数。只要没有读满,就继续等待;如果读多了,就把多出来的字节留在缓冲区,作为下一条消息的开头。
+
+很多二进制协议、RPC 协议都会用这种方式。实际设计时,协议头里通常不只放长度,还会放魔数、版本号、消息类型、序列号、序列化方式等字段。
+
+长度头方案也有坑。长度字段要约定字节序,通常使用网络字节序;还要限制最大包体长度,避免对端传一个特别大的长度值,把内存撑爆。线上做协议解析时,不能只考虑正常路径,还要处理半包、异常长度、连接中途关闭、恶意构造请求等情况。
+
+#### Nagle 算法和 Delayed ACK 为什么会让小包变慢?
+
+讲粘包时,经常会顺带问到 Nagle 算法。
+
+Nagle 算法的目标是减少小包数量。早期网络带宽有限,如果应用每次只写 1 个字节,TCP/IP 头部却有几十个字节,网络里就会充满“小包”,效率很低。RFC 896 讨论的就是这类 small-packet problem,并提出当连接上还有未确认数据时,新的小数据可以先暂缓发送,等 ACK 到来后再继续发送。
+
+Delayed ACK 是接收端的优化。接收端收到数据后,不一定立刻发 ACK,而是等一小段时间,看能不能把 ACK 和要返回的数据一起发出去,减少纯 ACK 包数量。RFC 9293 也把这种“少于每个数据段一个 ACK”的策略称为 delayed ACK。
+
+这两个机制单独看都有道理,放在一起就可能放大延迟。典型场景是:
+
+```
+客户端 write 小数据 A
+客户端马上 write 小数据 B
+客户端等待服务端响应
+```
+
+
+
+小数据 A 发出去了,小数据 B 可能因为 Nagle 算法暂存在发送缓冲区里,等待 A 的 ACK。服务端收到 A 后,如果暂时没有业务响应要返回,Delayed ACK 又可能延迟发送 ACK。于是发送端等 ACK,接收端等更多数据或等延迟确认定时器,延迟就被放大了。
+
+这类问题在短小 RPC、交互式协议、游戏同步、远程终端里更容易被感知。
+
+解决思路不是“无脑关 Nagle”。更稳的做法是:
+
+- 能合并的小写入,在应用层先合并成一次完整消息,再调用一次 `write()`。
+- 请求/响应模型里,尽量避免连续多次小 `write()` 后马上等待响应。
+- 对延迟敏感、消息很小的连接,可以评估开启 `TCP_NODELAY`,让小数据尽快发送。
+- 对吞吐优先、希望攒够数据再发的场景,可以在 Linux 上评估 `TCP_CORK`,但它不适合写跨平台代码。
+- 调参前先抓包确认,不要看到“慢”就直接改 socket 选项。
+
+在 Java 里,很多网络框架都会暴露 `TCP_NODELAY` 配置,例如 Netty 的 `ChannelOption.TCP_NODELAY`。它确实能降低小消息的等待时间,但也可能增加小包数量。对高 QPS 服务来说,这个 trade-off 要结合消息大小、RTT、吞吐、CPU 和网卡包量一起看。Linux `tcp(7)` 也说明,`TCP_NODELAY` 会关闭 Nagle 算法,而 `TCP_CORK` 则用于避免发送不完整帧、等应用确认“可以发了”再发送。
+
+#### 面试时怎么回答?
+
+可以这么回答:
+
+TCP 是面向字节流的。应用层写入的数据会进入内核缓冲区,TCP 只保证这些字节可靠、有序地到达对端,不保证一次 `send()` 对应一次 `recv()`,也不保留应用层消息边界。因此接收方可能一次读到多条消息,也可能只读到半条消息,这就是常说的粘包、拆包现象。
+
+UDP 是面向报文的。应用层交给 UDP 的一次数据会作为一个 UDP 数据报发送,接收端也是按数据报读取,所以天然保留消息边界。不过 UDP 不保证可靠到达,也不保证顺序。
+
+解决 TCP 粘包/拆包,本质是应用层协议自己定义消息边界。常见方案有固定长度、分隔符、长度头。工程里更常用长度头,因为它对二进制协议和变长消息更友好,但要处理字节序、最大长度限制、半包缓存和异常连接关闭等问题。
+
+
diff --git a/docs/cs-basics/network/tcp-connection-and-disconnection.md b/docs/cs-basics/network/tcp-connection-and-disconnection.md
index 63bc97f82c9..e38bae15837 100644
--- a/docs/cs-basics/network/tcp-connection-and-disconnection.md
+++ b/docs/cs-basics/network/tcp-connection-and-disconnection.md
@@ -1,103 +1,304 @@
---
title: TCP 三次握手和四次挥手(传输层)
+description: 一文讲清 TCP 三次握手与四次挥手:SEQ/ACK/SYN/FIN 如何同步,TIME_WAIT 与 2MSL 的原因,半连接队列(SYN Queue)与全连接队列(Accept Queue)的工作机制,以及 backlog/somaxconn/syncookies 在高并发与 SYN Flood 下的影响。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: TCP,三次握手,四次挥手,三次握手为什么,四次挥手为什么,TIME_WAIT,CLOSE_WAIT,2MSL,状态机,SEQ,ACK,SYN,FIN,RST,半连接队列,全连接队列,SYN队列,Accept队列,backlog,somaxconn,SYN Flood,syncookies
---
-为了准确无误地把数据送达目标处,TCP 协议采用了三次握手策略。
+TCP(Transmission Control Protocol)是一种**面向连接**、**可靠**的传输层协议。这里的“可靠”,通常体现在按序交付、差错检测、丢包重传、流量控制和拥塞控制等方面。
-## 建立连接-TCP 三次握手
+TCP 连接的建立和释放,最常被问到的就是三次握手和四次挥手。它们看起来像固定流程,背后其实是在同步序列号、确认双方收发能力,并尽量安全地释放连接状态。
+
+这篇文章主要回答几个问题:
+
+1. TCP 三次握手每一步分别做了什么?
+2. 为什么建立连接需要三次握手,而不是两次或四次?
+3. TCP 四次挥手每一步分别做了什么?
+4. `TIME_WAIT`、`CLOSE_WAIT`、半连接队列和全连接队列分别该怎么理解?
+
+> **术语约定**:本文正文统一使用 `SYN_RCVD`、`TIME_WAIT` 这类下划线写法;RFC 中常写作 `SYN-RECEIVED`、`TIME-WAIT`,Linux `ss` 命令中常显示为 `syn-recv`、`time-wait`。它们指向的是同一类 TCP 状态,只是不同语境下的写法不同。
+
+## 建立连接:TCP 三次握手

-建立一个 TCP 连接需要“三次握手”,缺一不可:
+在最常见的“一端主动发起连接、一端被动监听”的场景下,TCP 连接通常通过三次握手建立:
-- **一次握手**:客户端发送带有 SYN(SEQ=x) 标志的数据包 -> 服务端,然后客户端进入 **SYN_SEND** 状态,等待服务端的确认;
-- **二次握手**:服务端发送带有 SYN+ACK(SEQ=y,ACK=x+1) 标志的数据包 –> 客户端,然后服务端进入 **SYN_RECV** 状态;
-- **三次握手**:客户端发送带有 ACK(ACK=y+1) 标志的数据包 –> 服务端,然后客户端和服务端都进入**ESTABLISHED** 状态,完成 TCP 三次握手。
+1. **第一次握手(SYN)**:客户端向服务端发送一个 SYN(Synchronize Sequence Numbers)报文段,其中包含客户端生成的初始序列号(Initial Sequence Number,ISN),例如 `seq=x`。发送后,客户端进入 `SYN_SENT` 状态,等待服务端确认。
+2. **第二次握手(SYN+ACK)**:服务端收到 SYN 后,如果同意建立连接,会回复一个 SYN+ACK 报文段。这个报文段包含两个关键信息:
+ - **SYN**:服务端也需要同步自己的初始序列号,因此会携带服务端生成的 ISN,例如 `seq=y`。
+ - **ACK**:用于确认收到客户端的 SYN,确认号设置为客户端初始序列号加一,即 `ack=x+1`。
+ - 发送该报文段后,服务端进入 `SYN_RCVD` 状态。
+3. **第三次握手(ACK)**:客户端收到服务端的 SYN+ACK 后,会向服务端发送最终确认报文段,确认号为 `ack=y+1`。发送后,客户端进入 `ESTABLISHED` 状态。服务端收到这个 ACK 后,也进入 `ESTABLISHED` 状态。
-当建立了 3 次握手之后,客户端和服务端就可以传输数据啦!
+至此,双方完成初始序列号同步,并确认这条连接可以开始双向传输数据。
### 什么是半连接队列和全连接队列?
-在 TCP 三次握手过程中,Linux 内核会维护两个队列来管理连接请求:
+```mermaid
+sequenceDiagram
+ autonumber
+ participant C as 客户端 Client
+ participant K as 服务端内核 TCP
+ box 服务端内核队列
+ participant SQ as 半连接队列 SYN queue
+ participant AQ as 全连接队列 Accept queue
+ end
+ participant App as 用户态应用 Server app
+
+ C->>K: SYN
+ K-->>C: SYN+ACK
+ Note over SQ: 内核为该连接创建请求条目 连接状态 SYN_RCVD 放入 SYN queue
+
+ C->>K: ACK 第三次握手
+ Note over SQ,AQ: 内核收到 ACK 后完成握手 将连接从 SYN queue 迁移到 Accept queue 队列未满才可进入
+ Note over AQ: 连接已完成 可被 accept 连接状态 ESTABLISHED
+
+ App->>K: accept
+ K-->>App: 返回已就绪的 socket
+ Note over AQ: 该连接从 Accept queue 移除
+```
+
+在 TCP 三次握手过程中,服务端内核通常会用两个队列来管理连接请求。下面以常见 Linux 行为为例,不同操作系统、内核版本、socket 选项和部署环境可能会有细节差异。
+
+1. **半连接队列(SYN Queue)**:
+ - 保存“握手未完成”的请求。服务端收到 SYN 并回复 SYN+ACK 后,连接进入 `SYN_RCVD`,等待客户端最终 ACK。
+ - 如果一直收不到 ACK,内核会按重传策略重发 SYN+ACK,最终超时清理。
+ - 常见相关参数包括 `net.ipv4.tcp_max_syn_backlog`。在 SYN Flood 场景下,还会涉及 `net.ipv4.tcp_syncookies`。
+2. **全连接队列(Accept Queue)**:
+
+ - 保存“握手已完成但应用还没有 accept”的连接。服务端收到最终 ACK 后,连接变为 `ESTABLISHED`,并进入全连接队列,等待应用层 `accept()` 取走。
+ - 队列容量受 `listen(fd, backlog)` 和系统上限 `net.core.somaxconn` 共同影响。实践中常见有效上限可以近似理解为 `min(backlog, somaxconn)`,具体行为仍要看内核版本和应用配置。
+
+ 总结一下:
+
+| 队列 | 作用 | 状态 | 移出条件 |
+| -------------------------- | -------------------------------------- | ------------- | ------------------------ |
+| 半连接队列(SYN Queue) | 保存未完成握手的连接 | `SYN_RCVD` | 收到 ACK / 超时重传失败 |
+| 全连接队列(Accept Queue) | 保存已完成握手、等待应用 accept 的连接 | `ESTABLISHED` | 被应用层 `accept()` 取出 |
+
+当全连接队列满时,`net.ipv4.tcp_abort_on_overflow` 会影响处理策略:
+
+- `0`(默认):Linux 通常不会立即返回 RST,而可能丢弃第三次握手 ACK,使服务端继续停留在握手未完全完成的状态,并重传 SYN+ACK。客户端侧可能已经认为 `connect()` 成功,但首包发送后迟迟没有响应,最终表现为首包阻塞、读超时或重试。
+- `1`:直接对客户端回复 `RST`,让连接快速失败。
+
+排查时可以用 `ss -ltn` 看监听 socket。对于 `LISTEN` 状态,`Recv-Q` 通常表示当前 backlog 中等待应用 accept 的连接数,`Send-Q` 表示 socket backlog 上限。如果 `Recv-Q` 长时间接近 `Send-Q`,就要重点怀疑应用 accept 不及时、backlog 偏小、线程池卡住、GC 抖动或者短时间连接突刺。
+
+当半连接队列满时,如果 `tcp_syncookies=1`,Linux 会在 SYN backlog 溢出时启用 SYN Cookie:服务端把必要信息编码进返回的 SYN+ACK 中,而不是为每个请求都保留完整的半连接状态。只有收到合法的最终 ACK 后,内核才会重建连接所需的信息。
+
+但 SYN Cookie 是防护手段,不是扩容手段。它能缓解 SYN Flood 对半连接队列的冲击,但仍会消耗 CPU;如果攻击流量已经打满带宽,SYN Cookie 也无法从根本上恢复可用性。另外,SYN Cookie 模式下部分 TCP 扩展能力可能受限,在高延迟、高带宽链路下可能出现性能退化。`tcp_syncookies=2` 更偏测试用途,不建议作为生产环境默认配置。
+
+### 为什么要三次握手?
+
+TCP 三次握手主要做两件事:**同步双方的初始序列号**,并且**确认双方的收发路径是可用的**。真正的数据可靠交付,还要依赖后续传输过程中的确认、重传、窗口控制和拥塞控制。
+
+#### 1. 确认双方收发能力,并同步初始序列号
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant C as 客户端 Client
+ participant S as 服务端 Server
+
+ Note over C,S: 目标 同步双方 ISN 并确认双向可达
+
+ C->>S: SYN seq=ISN_C
+ Note right of S: 服务端知道 C→S 方向可达 客户端能发 服务端能收
+ Note right of S: 服务端状态 SYN_RCVD
+
+ S->>C: SYN+ACK seq=ISN_S ack=ISN_C+1
+ Note left of C: 客户端知道 S→C 方向可达 也知道服务端收到了自己的 SYN
+
+ C->>S: ACK seq=ISN_C+1 ack=ISN_S+1
+ Note left of C: 客户端状态 ESTABLISHED
+ Note right of S: 服务端知道客户端收到了 SYN+ACK 握手闭环 双方 ISN 同步完成
+ Note right of S: 服务端状态 ESTABLISHED
+
+ Note over C,S: 连接建立 可以开始传输数据
+```
-1. **半连接队列**(也称 SYN Queue):当服务端收到客户端的 SYN 请求时,此时双方还没有完全建立连接,它会把半连接状态的连接放在半连接队列。
-2. **全连接队列**(也称 Accept Queue):当服务端收到客户端对 ACK 响应时,意味着三次握手成功完成,服务端会将该连接从半连接队列移动到全连接队列。如果未收到客户端的 ACK 响应,会进行重传,重传的等待时间通常是指数增长的。如果重传次数超过系统规定的最大重传次数,系统将从半连接队列中删除该连接信息。
+TCP 依赖序列号(SEQ)和确认号(ACK)来保证数据有序、去重和重传。三次握手通过交换并确认双方的 ISN,让两端对“从哪个序号开始收发数据”达成一致,同时避免只凭单向信息就进入已建立状态。
-这两个队列的存在是为了处理并发连接请求,确保服务端能够有效地管理新的连接请求。另外,新的连接请求被拒绝或忽略除了和每个队列的大小限制有关系之外,还和很多其他因素有关系,这里就不详细介绍了,整体逻辑比较复杂。
+可以用下面这张表来记:
-### 为什么要三次握手?
+| 步骤 | 报文 | 能确认什么 |
+| ---- | ------------ | ---------------------------------------------------------------------- |
+| 1 | C→S:SYN | 服务端知道:客户端能发,服务端能收,C→S 方向可达 |
+| 2 | S→C:SYN+ACK | 客户端知道:服务端能发,客户端能收;同时确认服务端收到了自己的 SYN |
+| 3 | C→S:ACK | 服务端知道:客户端收到了 SYN+ACK,S→C 方向也被服务端确认;至此握手闭环 |
-三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。
+注意,第 2 步之后只是客户端确认了双向可达,服务端还不知道客户端是否收到了 SYN+ACK。服务端只有收到第 3 次握手的 ACK 后,才真正确认这个闭环。
-1. **第一次握手**:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常
-2. **第二次握手**:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
-3. **第三次握手**:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常
+#### 2. 防止已失效的连接请求被错误建立
-三次握手就能确认双方收发功能都正常,缺一不可。
+```mermaid
+sequenceDiagram
+ participant C as 客户端 Client
+ participant S as 服务端 Server
-更详细的解答可以看这个:[TCP 为什么是三次握手,而不是两次或四次? - 车小胖的回答 - 知乎](https://www.zhihu.com/question/24853633/answer/115173386) 。
+ Note over C,S: 场景 旧的 SYN 报文在网络中滞留
-### 第 2 次握手传回了 ACK,为什么还要传回 SYN?
+ C->>S: 1. 发送 SYN 旧请求 滞留中
+ Note over C: 客户端超时 放弃该请求
-服务端传回发送端所发送的 ACK 是为了告诉客户端:“我接收到的信息确实就是你所发送的信号了”,这表明从客户端到服务端的通信是正常的。回传 SYN 则是为了建立并确认从服务端到客户端的通信。
+ C->>S: 2. 发送 SYN 新请求
+ S-->>C: 3. 建立连接并正常释放
-> SYN 同步序列编号(Synchronize Sequence Numbers) 是 TCP/IP 建立连接时使用的握手信号。在客户机和服务端之间建立正常的 TCP 网络连接时,客户机首先发出一个 SYN 消息,服务端使用 SYN-ACK 应答表示接收到了这个消息,最后客户机再以 ACK(Acknowledgement)消息响应。这样在客户机和服务端之间才能建立起可靠的 TCP 连接,数据才可以在客户机和服务端之间传递。
+ rect rgb(255, 240, 240)
+ Note right of S: 此时旧 SYN 终于到达服务端
+ S->>C: 4. 发送 SYN+ACK 针对旧请求
+
+ alt 如果是两次握手
+ Note right of S: 假设服务端回复 SYN+ACK 后 就认为连接建立
+ Note right of S: 错误建立连接 分配资源 造成浪费
+ else 如果是三次握手
+ Note left of C: 客户端无该连接状态 或认为这是非期望报文
+ C->>S: 5. 发送 RST 或直接丢弃
+ Note right of S: 收到 RST 立即清理 或等不到 ACK 后超时清理
+ end
+ end
+```
+
+设想一个场景:客户端发送的第一个连接请求 SYN1 因网络延迟而滞留。客户端超时后,重新发送 SYN2,并成功建立连接,数据传输完毕后连接也释放了。此时,延迟的 SYN1 才到达服务端。
+
+- **如果是两次握手**:服务端收到这个失效的 SYN1 后,可能误认为这是一个新的连接请求,并立即分配资源、建立连接。但客户端已经没有这个连接意图,不会继续配合传输,服务端就会单方面维持一个无效连接。
+- **有了第三次握手**:服务端收到失效的 SYN1 并回复 SYN+ACK 后,还要等待客户端最终 ACK。由于客户端当前没有这个连接状态,它可能直接丢弃,也可能发送 RST。服务端收不到合法 ACK,最终就会清理这个错误连接。
+
+所以,三次握手不是“多发一次包而已”,它让连接建立过程形成闭环,避免网络中的延迟、重复历史请求干扰新的连接。
+
+### 第 2 次握手已经传回 ACK,为什么还要传回 SYN?
+
+第二次握手里的 ACK 是为了确认“服务端收到了客户端的 SYN”,也就是确认 C→S 方向的请求已经到达。
+
+同时携带 SYN,是因为服务端也需要把自己的 ISN 同步给客户端,并要求客户端确认。只有双方的 ISN 都完成同步,后续可靠传输才有共同的序列号起点。
+
+简言之:ACK 表示“我收到了你的 SYN”,SYN 表示“我也要同步我的初始序列号,请你确认”。
+
+> SYN(Synchronize Sequence Numbers)是 TCP 建立连接时使用的同步信号。客户端先发送 SYN,服务端使用 SYN+ACK 应答,最后客户端再用 ACK 确认。这样双方才能完成初始序列号同步,建立一条可用于可靠数据传输的 TCP 连接。
### 三次握手过程中可以携带数据吗?
-在 TCP 三次握手过程中,第三次握手是可以携带数据的(客户端发送完 ACK 确认包之后就进入 ESTABLISHED 状态了),这一点在 RFC 793 文档中有提到。也就是说,一旦完成了前两次握手,TCP 协议允许数据在第三次握手时开始传输。
+普通 TCP 中,第三次握手的 ACK 可以携带数据。RFC 9293 也允许连接同步阶段出现携带数据的报文,但接收端在确认数据有效前,不能把这部分数据交付给应用;通常需要等连接进入 `ESTABLISHED` 后,应用层才能读到这些数据。
+
+如果第三次握手的 ACK 丢失,但客户端随后发送了一个携带数据且带 ACK 标志的报文,服务端收到后可以把它视为有效的第三次握手确认。连接被认为建立后,服务端再继续处理该数据。
-如果第三次握手的 ACK 确认包丢失,但是客户端已经开始发送携带数据的包,那么服务端在收到这个携带数据的包时,如果该包中包含了 ACK 标记,服务端会将其视为有效的第三次握手确认。这样,连接就被认为是建立的,服务端会处理该数据包,并继续正常的数据传输流程。
+需要注意,这和 TCP Fast Open(TFO)不是一回事。TFO 讨论的是第一次 SYN 就携带应用数据,需要客户端、服务端和系统配置共同支持,不是普通 TCP 默认行为。
-## 断开连接-TCP 四次挥手
+## 断开连接:TCP 四次挥手

-断开一个 TCP 连接则需要“四次挥手”,缺一不可:
+TCP 是全双工通信,两端的发送方向彼此独立。关闭连接时,通常需要两个方向分别完成“我不发了”和“我确认你不发了”的过程,所以逻辑上常被讲成“四次挥手”。
+
+不过要注意:四次挥手说的是逻辑动作,不一定意味着抓包时总能看到 4 个独立报文段。在某些场景下,ACK 和 FIN 可以合并在同一个报文段里。
+
+典型流程如下:
+
+1. **第一次挥手(FIN)**:客户端,或者任意一方,决定关闭自己的发送方向时,会发送一个 FIN 报文段,表示自己已经没有数据要发送了。该报文段包含一个序列号,例如 `seq=u`。发送后,主动关闭方进入 `FIN_WAIT_1` 状态。
+2. **第二次挥手(ACK)**:服务端收到 FIN 后,会回复 ACK,确认号为 `ack=u+1`。发送后,服务端进入 `CLOSE_WAIT` 状态。客户端收到 ACK 后,进入 `FIN_WAIT_2` 状态。此时连接处于**半关闭(Half-Close)**状态:客户端到服务端的发送方向已关闭,但服务端仍然可以继续向客户端发送剩余数据。
+3. **第三次挥手(FIN)**:当服务端确认剩余数据都发送完毕后,也会发送 FIN,表示自己也准备关闭发送方向。该报文段同样包含一个序列号,例如 `seq=y`。发送后,服务端进入 `LAST_ACK` 状态,等待客户端最终确认。
+4. **第四次挥手(ACK)**:客户端收到服务端的 FIN 后,回复最终 ACK,确认号为 `ack=y+1`。发送后,客户端进入 `TIME_WAIT` 状态。服务端收到这个 ACK 后进入 `CLOSED`。客户端则在 `TIME_WAIT` 状态等待 2MSL 后,最终进入 `CLOSED`。
-1. **第一次挥手**:客户端发送一个 FIN(SEQ=x) 标志的数据包->服务端,用来关闭客户端到服务端的数据传送。然后客户端进入 **FIN-WAIT-1** 状态。
-2. **第二次挥手**:服务端收到这个 FIN(SEQ=X) 标志的数据包,它发送一个 ACK (ACK=x+1)标志的数据包->客户端 。然后服务端进入 **CLOSE-WAIT** 状态,客户端进入 **FIN-WAIT-2** 状态。
-3. **第三次挥手**:服务端发送一个 FIN (SEQ=y)标志的数据包->客户端,请求关闭连接,然后服务端进入 **LAST-ACK** 状态。
-4. **第四次挥手**:客户端发送 ACK (ACK=y+1)标志的数据包->服务端,然后客户端进入**TIME-WAIT**状态,服务端在收到 ACK (ACK=y+1)标志的数据包后进入 CLOSE 状态。此时如果客户端等待 **2MSL** 后依然没有收到回复,就证明服务端已正常关闭,随后客户端也可以关闭连接了。
+> 注意区分:**半关闭(Half-Close)**指一个方向已经发送 FIN,另一个方向仍可继续发送数据;**半开连接(Half-Open Connection)**通常指一端崩溃、重启或状态丢失后,另一端仍以为连接存在。两者不是同一个概念。
-**只要四次挥手没有结束,客户端和服务端就可以继续传输数据!**
+TCP 连接建立与关闭的常见状态迁移路径如下。图中省略了同时打开、同时关闭、RST、CLOSING 等少见或异常分支。
+
+
### 为什么要四次挥手?
-TCP 是全双工通信,可以双向传输数据。任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了 TCP 连接。
+因为 TCP 是全双工的。A 不想发了,不代表 B 也立刻没有数据要发。
+
+举个例子,A 和 B 打电话,通话即将结束:
-举个例子:A 和 B 打电话,通话即将结束后。
+1. A 说:“我没什么要说的了。”(A 发 FIN)
+2. B 回答:“我知道了。”但 B 可能还有话要说。(B 回 ACK)
+3. B 继续说完剩下的话,最后说:“我也说完了。”(B 发 FIN)
+4. A 回答:“知道了。”(A 回 ACK)
-1. **第一次挥手**:A 说“我没啥要说的了”
-2. **第二次挥手**:B 回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话
-3. **第三次挥手**:于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”
-4. **第四次挥手**:A 回答“知道了”,这样通话才算结束。
+这对应到 TCP 中,就是两个方向分别关闭、分别确认。
### 为什么不能把服务端发送的 ACK 和 FIN 合并起来,变成三次挥手?
-因为服务端收到客户端断开连接的请求时,可能还有一些数据没有发完,这时先回复 ACK,表示接收到了断开连接的请求。等到数据发完之后再发 FIN,断开服务端到客户端的数据传送。
+```mermaid
+sequenceDiagram
+ autonumber
+ participant C as 客户端
+ participant K as 服务端内核
+ participant A as 服务端应用
+
+ Note over C,K: 客户端发起关闭
+ C->>K: FIN
+ Note right of K: 内核立即回复 ACK 用于确认对端 FIN
+ K-->>C: ACK
+ Note right of K: 服务端状态变为 CLOSE_WAIT
+
+ Note over K,A: 应用处理阶段
+ K->>A: 通知本端应用 对端已关闭发送方向 例如 read 返回 0
+ A->>A: 读取和处理剩余数据
+ A->>A: 发送最后响应
+ A->>K: 调用 close 或 shutdown
+
+ Note right of K: 发送本端 FIN 并进入 LAST_ACK
+ K-->>C: FIN
+ Note left of C: 客户端回复 ACK 并进入 TIME_WAIT
+ C->>K: ACK
+ Note right of K: 服务端收到最终 ACK 进入 CLOSED
+```
+
+关键原因是:**回复 ACK** 和 **发送 FIN** 的触发时机通常不同。
+
+- 当服务端收到客户端 FIN 时,内核协议栈会立即回复 ACK,确认“我收到了你要关闭发送方向的请求”。此时服务端进入 `CLOSE_WAIT`,等待本端应用处理剩余数据。
+- 只有当服务端应用处理完毕,并调用 `close()` 或 `shutdown()` 后,内核才会发送本端 FIN。
+- 因此,“内核自动回 ACK”和“应用决定发 FIN”在时间上是解耦的,通常无法合并。只有在服务端恰好也准备立即关闭时,才可能出现 FIN+ACK 合并在一个报文段中的情况。
### 如果第二次挥手时服务端的 ACK 没有送达客户端,会怎样?
-客户端没有收到 ACK 确认,会重新发送 FIN 请求。
+客户端发送第一次 FIN 后进入 `FIN_WAIT_1`,并启动重传计时器。如果在超时时间内没有收到对端对 FIN 的确认 ACK,客户端会重传 FIN。
+
+服务端如果收到重复 FIN,通常会再次发送 ACK。如果由于网络问题 ACK 一直无法送达,客户端在达到一定重试或超时阈值后,可能报错或放弃。具体行为受实现和参数影响,例如 Linux 中的 `tcp_retries2` 等。
+
+### 为什么第四次挥手后要等待 2MSL?
+
+第四次挥手时,主动关闭方发送给被动关闭方的最后一个 ACK 可能丢失。如果被动关闭方没有收到 ACK,就会重传 FIN。主动关闭方还在 `TIME_WAIT` 里,就能再次回复 ACK。
+
+如果主动关闭方发完最后一个 ACK 后立刻进入 `CLOSED`,当对端重传 FIN 到达时,本端可能已经没有对应连接状态,只能回复 RST,导致对端看到异常关闭或连接被重置。
-### 为什么第四次挥手客户端需要等待 2\*MSL(报文段最长寿命)时间后才进入 CLOSED 状态?
+```mermaid
+sequenceDiagram
+ participant A as 主动关闭方
+ participant B as 被动关闭方
-第四次挥手时,客户端发送给服务端的 ACK 有可能丢失,如果服务端因为某些原因而没有收到 ACK 的话,服务端就会重发 FIN,如果客户端在 2\*MSL 的时间内收到了 FIN,就会重新发送 ACK 并再次等待 2MSL,防止 Server 没有收到 ACK 而不断重发 FIN。
+ B->>A: FIN
+ A-->>B: ACK 丢失
+ Note over A: A 进入 TIME_WAIT 没有立刻释放连接
+ B->>A: 重传 FIN
+ A-->>B: 再次 ACK
+ Note over B: B 收到 ACK 后进入 CLOSED
+```
-> **MSL(Maximum Segment Lifetime)** : 一个片段在网络中最大的存活时间,2MSL 就是一个发送和一个回复所需的最大时间。如果直到 2MSL,Client 都没有再次收到 FIN,那么 Client 推断 ACK 已经被成功接收,则结束 TCP 连接。
+**MSL(Maximum Segment Lifetime)** 是报文段在网络中的最大生存时间。2MSL 不是一次请求-响应的最大 RTT,而是一个保守等待窗口:既给最后 ACK 丢失后的 FIN 重传留出处理机会,也尽量保证旧连接中的延迟报文从网络中消失。
+
+需要注意,RFC 里的 MSL 是协议层概念,具体系统实现可能不同。Linux 常见实现中,`TIME_WAIT` 保留时间通常是 60 秒。还有一个常见误区:`tcp_fin_timeout` 控制的是 orphaned connection 的 `FIN_WAIT_2` 超时,不是 `TIME_WAIT`。想缓解 `TIME_WAIT` 带来的端口压力,优先看连接复用、端口范围、主动关闭方和 `tcp_tw_reuse` 条件,而不是试图用 `tcp_fin_timeout` 缩短 `TIME_WAIT`。
+
+## TIME_WAIT 常见问题:为什么要等、会不会出问题、能不能复用?
+
+这部分内容已单独成文,详见 [TCP TIME_WAIT 详解:为什么要等、会不会出问题、能不能复用?](./tcp-time-wait.md)。
## 参考
- 《计算机网络(第 7 版)》
-
- 《图解 HTTP》
-
- TCP and UDP Tutorial:
-
- 从一次线上问题说起,详解 TCP 半连接队列、全连接队列:
+- RFC 9293: Transmission Control Protocol (TCP):
+- RFC 1337: TIME-WAIT Assassination Hazards in TCP:
+- Linux 内核 ip-sysctl 文档:
+- SoByte - 为什么 TCP 需要 TIME_WAIT 状态:
diff --git a/docs/cs-basics/network/tcp-reliability-guarantee.md b/docs/cs-basics/network/tcp-reliability-guarantee.md
index d4c9bea80ed..202112ee981 100644
--- a/docs/cs-basics/network/tcp-reliability-guarantee.md
+++ b/docs/cs-basics/network/tcp-reliability-guarantee.md
@@ -1,31 +1,47 @@
---
title: TCP 传输可靠性保障(传输层)
+description: 系统梳理 TCP 的可靠性保障机制,覆盖重传/选择确认、流量与拥塞控制,明确端到端可靠传输的实现要点。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: TCP,可靠性,重传,SACK,流量控制,拥塞控制,滑动窗口,校验和
---
+TCP 常被说成可靠传输协议,但“可靠”不是一句抽象承诺,而是一组具体机制共同配合出来的结果。
+
+丢包要重传,乱序要重排,接收方处理不过来要流量控制,网络拥塞时要主动降速。把这些机制串起来,才能真正理解 TCP 为什么能在不可靠的 IP 网络之上提供可靠传输。
+
+这篇文章主要回答几个问题:
+
+1. TCP 通过哪些机制保证数据可靠到达?
+2. 超时重传、快速重传、SACK、D-SACK 分别解决什么问题?
+3. TCP 如何通过滑动窗口实现流量控制?
+4. 拥塞控制中的慢开始、拥塞避免、快重传、快恢复分别怎么理解?
+
## TCP 如何保证传输的可靠性?
1. **基于数据块传输**:应用数据被分割成 TCP 认为最适合发送的数据块,再传输给网络层,数据块被称为报文段或段。
2. **对失序数据包重新排序以及去重**:TCP 为了保证不发生丢包,就给每个包一个序列号,有了序列号能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据就可以实现数据包去重。
-3. **校验和** : TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
-4. **重传机制** : 在数据包丢失或延迟的情况下,重新发送数据包,直到收到对方的确认应答(ACK)。TCP 重传机制主要有:基于计时器的重传(也就是超时重传)、快速重传(基于接收端的反馈信息来引发重传)、SACK(在快速重传的基础上,返回最近收到的报文段的序列号范围,这样客户端就知道,哪些数据包已经到达服务器了)、D-SACK(重复 SACK,在 SACK 的基础上,额外携带信息,告知发送方有哪些数据包自己重复接收了)。关于重传机制的详细介绍,可以查看[详解 TCP 超时与重传机制](https://zhuanlan.zhihu.com/p/101702312)这篇文章。
-5. **流量控制** : TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议(TCP 利用滑动窗口实现流量控制)。
-6. **拥塞控制** : 当网络拥塞时,减少数据的发送。TCP 在发送数据的时候,需要考虑两个因素:一是接收方的接收能力,二是网络的拥塞程度。接收方的接收能力由滑动窗口表示,表示接收方还有多少缓冲区可以用来接收数据。网络的拥塞程度由拥塞窗口表示,它是发送方根据网络状况自己维护的一个值,表示发送方认为可以在网络中传输的数据量。发送方发送数据的大小是滑动窗口和拥塞窗口的最小值,这样可以保证发送方既不会超过接收方的接收能力,也不会造成网络的过度拥塞。
+3. **校验和**:TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
+4. **重传机制**:在数据包丢失或延迟的情况下,重新发送数据包,直到收到对方的确认应答(ACK)。TCP 重传机制主要有:基于计时器的重传(也就是超时重传)、快速重传(基于接收端的反馈信息来引发重传)、SACK(在快速重传的基础上,返回最近收到的报文段的序列号范围,这样客户端就知道,哪些数据包已经到达服务器了)、D-SACK(重复 SACK,在 SACK 的基础上,额外携带信息,告知发送方有哪些数据包自己重复接收了)。关于重传机制的详细介绍,可以查看[详解 TCP 超时与重传机制](https://zhuanlan.zhihu.com/p/101702312)这篇文章。
+5. **流量控制**:TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议(TCP 利用滑动窗口实现流量控制)。
+6. **拥塞控制**:当网络拥塞时,减少数据的发送。TCP 在发送数据的时候,需要考虑两个因素:一是接收方的接收能力,二是网络的拥塞程度。接收方的接收能力由滑动窗口表示,表示接收方还有多少缓冲区可以用来接收数据。网络的拥塞程度由拥塞窗口表示,它是发送方根据网络状况自己维护的一个值,表示发送方认为可以在网络中传输的数据量。发送方发送数据的大小是滑动窗口和拥塞窗口的最小值,这样可以保证发送方既不会超过接收方的接收能力,也不会造成网络的过度拥塞。
## TCP 如何实现流量控制?
**TCP 利用滑动窗口实现流量控制。流量控制是为了控制发送方发送速率,保证接收方来得及接收。** 接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。
-**为什么需要流量控制?** 这是因为双方在通信的时候,发送方的速率与接收方的速率是不一定相等,如果发送方的发送速率太快,会导致接收方处理不过来。如果接收方处理不过来的话,就只能把处理不过来的数据存在 **接收缓冲区(Receiving Buffers)** 里(失序的数据包也会被存放在缓存区里)。如果缓存区满了发送方还在狂发数据的话,接收方只能把收到的数据包丢掉。出现丢包问题的同时又疯狂浪费着珍贵的网络资源。因此,我们需要控制发送方的发送速率,让接收方与发送方处于一种动态平衡才好。
+**为什么需要流量控制?** 这是因为双方在通信的时候,发送方的速率与接收方的速率是不一定相等,如果发送方的发送速率太快,会导致接收方处理不过来。如果接收方处理不过来的话,就只能把处理不过来的数据存在 **接收缓冲区(Receiving Buffers)** 里(失序的数据包也会被存放在缓存区里)。如果缓存区满了发送方还在狂发数据的话,接收方只能把收到的数据包丢掉。出现丢包问题的同时又疯狂浪费着珍贵的网络资源。因此,我们需要控制发送方的发送速率,让接收方与发送方处于一种动态平衡才好。
这里需要注意的是(常见误区):
- 发送端不等同于客户端
- 接收端不等同于服务端
-TCP 为全双工(Full-Duplex, FDX)通信,双方可以进行双向通信,客户端和服务端既可能是发送端又可能是服务端。因此,两端各有一个发送缓冲区与接收缓冲区,两端都各自维护一个发送窗口和一个接收窗口。接收窗口大小取决于应用、系统、硬件的限制(TCP 传输速率不能大于应用的数据处理速率)。通信双方的发送窗口和接收窗口的要求相同
+TCP 为全双工(Full-Duplex,FDX)通信,双方可以进行双向通信,客户端和服务端既可能是发送端又可能是服务端。因此,两端各有一个发送缓冲区与接收缓冲区,两端都各自维护一个发送窗口和一个接收窗口。接收窗口大小取决于应用、系统、硬件的限制(TCP 传输速率不能大于应用的数据处理速率)。通信双方的发送窗口和接收窗口的要求相同。
**TCP 发送窗口可以划分成四个部分**:
@@ -64,15 +80,15 @@ TCP 为全双工(Full-Duplex, FDX)通信,双方可以进行双向通信,客

-为了进行拥塞控制,TCP 发送方要维持一个 **拥塞窗口(cwnd)** 的状态变量。拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个。
+为了进行拥塞控制,TCP 发送方要维持一个 **拥塞窗口(cwnd)** 的状态变量。拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个。
-TCP 的拥塞控制采用了四种算法,即 **慢开始**、 **拥塞避免**、**快重传** 和 **快恢复**。在网络层也可以使路由器采用适当的分组丢弃策略(如主动队列管理 AQM),以减少网络拥塞的发生。
+TCP 的拥塞控制采用了四种算法,即 **慢开始**、**拥塞避免**、**快重传** 和 **快恢复**。在网络层也可以使路由器采用适当的分组丢弃策略(如主动队列管理 AQM),以减少网络拥塞的发生。
-- **慢开始:** 慢开始算法的思路是当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么可能会引起网络阻塞,因为现在还不知道网络的符合情况。经验表明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。cwnd 初始值为 1,每经过一个传播轮次,cwnd 加倍。
-- **拥塞避免:** 拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢增大,即每经过一个往返时间 RTT 就把发送方的 cwnd 加 1.
-- **快重传与快恢复:** 在 TCP/IP 中,快速重传和恢复(fast retransmit and recovery,FRR)是一种拥塞控制算法,它能快速恢复丢失的数据包。没有 FRR,如果数据包丢失了,TCP 将会使用定时器来要求传输暂停。在暂停的这段时间内,没有新的或复制的数据包被发送。有了 FRR,如果接收机接收到一个不按顺序的数据段,它会立即给发送机发送一个重复确认。如果发送机接收到三个重复确认,它会假定确认件指出的数据段丢失了,并立即重传这些丢失的数据段。有了 FRR,就不会因为重传时要求的暂停被耽误。 当有单独的数据包丢失时,快速重传和恢复(FRR)能最有效地工作。当有多个数据信息包在某一段很短的时间内丢失时,它则不能很有效地工作。
+- **慢开始**:慢开始算法的思路是当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么可能会引起网络阻塞,因为现在还不知道网络的负荷情况。经验表明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。cwnd 初始值为 1,每经过一个传播轮次,cwnd 加倍。
+- **拥塞避免**:拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢增大,即每经过一个往返时间 RTT 就把发送方的 cwnd 加 1。
+- **快重传与快恢复**:在 TCP/IP 中,快速重传和恢复(fast retransmit and recovery,FRR)是一种拥塞控制算法,它能快速恢复丢失的数据包。没有 FRR,如果数据包丢失了,TCP 将会使用定时器来要求传输暂停。在暂停的这段时间内,没有新的或复制的数据包被发送。有了 FRR,如果接收机接收到一个不按顺序的数据段,它会立即给发送机发送一个重复确认。如果发送机接收到三个重复确认,它会假定确认件指出的数据段丢失了,并立即重传这些丢失的数据段。有了 FRR,就不会因为重传时要求的暂停被耽误。当有单独的数据包丢失时,快速重传和恢复(FRR)能最有效地工作。当有多个数据信息包在某一段很短的时间内丢失时,它则不能很有效地工作。
-## ARQ 协议了解吗?
+## ARQ 协议了解吗?
**自动重传请求**(Automatic Repeat-reQuest,ARQ)是 OSI 模型中数据链路层和传输层的错误纠正协议之一。它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。如果发送方在发送后一段时间之内没有收到确认信息(Acknowledgements,就是我们常说的 ACK),它通常会重新发送,直到收到确认或者重试超过一定的次数。
@@ -80,19 +96,19 @@ ARQ 包括停止等待 ARQ 协议和连续 ARQ 协议。
### 停止等待 ARQ 协议
-停止等待协议是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认(回复 ACK)。如果过了一段时间(超时时间后),还是没有收到 ACK 确认,说明没有发送成功,需要重新发送,直到收到确认后再发下一个分组;
+停止等待协议是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认(回复 ACK)。如果过了一段时间(超时时间后),还是没有收到 ACK 确认,说明没有发送成功,需要重新发送,直到收到确认后再发下一个分组。
在停止等待协议中,若接收方收到重复分组,就丢弃该分组,但同时还要发送确认。
-**1) 无差错情况:**
+**1)无差错情况:**
-发送方发送分组,接收方在规定时间内收到,并且回复确认.发送方再次发送。
+发送方发送分组,接收方在规定时间内收到,并且回复确认。发送方再次发送。
-**2) 出现差错情况(超时重传):**
+**2)出现差错情况(超时重传):**
停止等待协议中超时重传是指只要超过一段时间仍然没有收到确认,就重传前面发送过的分组(认为刚才发送过的分组丢失了)。因此每发送完一个分组需要设置一个超时计时器,其重传时间应比数据在分组传输的平均往返时间更长一些。这种自动重传方式常称为 **自动重传请求 ARQ** 。另外在停止等待协议中若收到重复分组,就丢弃该分组,但同时还要发送确认。
-**3) 确认丢失和确认迟到**
+**3)确认丢失和确认迟到**
- **确认丢失**:确认消息在传输过程丢失。当 A 发送 M1 消息,B 收到后,B 向 A 发送了一个 M1 确认消息,但却在传输过程中丢失。而 A 并不知道,在超时计时过后,A 重传 M1 消息,B 再次收到该消息后采取以下两点措施:1. 丢弃这个重复的 M1 消息,不向上层交付。 2. 向 A 发送确认消息。(不会认为已经发送过了,就不再发送。A 能重传,就证明 B 的确认消息丢失)。
- **确认迟到**:确认消息在传输过程中迟到。A 发送 M1 消息,B 收到并发送确认。在超时时间内没有收到确认消息,A 重传 M1 消息,B 仍然收到并继续发送确认消息(B 收到了 2 份 M1)。此时 A 收到了 B 第二次发送的确认消息。接着发送其他数据。过了一会,A 收到了 B 第一次发送的对 M1 的确认消息(A 也收到了 2 份确认消息)。处理如下:1. A 收到重复的确认后,直接丢弃。2. B 收到重复的 M1 后,也直接丢弃重复的 M1。
@@ -101,28 +117,28 @@ ARQ 包括停止等待 ARQ 协议和连续 ARQ 协议。
连续 ARQ 协议可提高信道利用率。发送方维持一个发送窗口,凡位于发送窗口内的分组可以连续发送出去,而不需要等待对方确认。接收方一般采用累计确认,对按序到达的最后一个分组发送确认,表明到这个分组为止的所有分组都已经正确收到了。
-- **优点:** 信道利用率高,容易实现,即使确认丢失,也不必重传。
-- **缺点:** 不能向发送方反映出接收方已经正确收到的所有分组的信息。 比如:发送方发送了 5 条 消息,中间第三条丢失(3 号),这时接收方只能对前两个发送确认。发送方无法知道后三个分组的下落,而只好把后三个全部重传一次。这也叫 Go-Back-N(回退 N),表示需要退回来重传已经发送过的 N 个消息。
+- **优点**:信道利用率高,容易实现,即使确认丢失,也不必重传。
+- **缺点**:不能向发送方反映出接收方已经正确收到的所有分组的信息。比如:发送方发送了 5 条消息,中间第三条丢失(3 号),这时接收方只能对前两个发送确认。发送方无法知道后三个分组的下落,而只好把后三个全部重传一次。这也叫 Go-Back-N(回退 N),表示需要退回来重传已经发送过的 N 个消息。
## 超时重传如何实现?超时重传时间怎么确定?
-当发送方发送数据之后,它启动一个定时器,等待目的端确认收到这个报文段。接收端实体对已成功收到的包发回一个相应的确认信息(ACK)。如果发送端实体在合理的往返时延(RTT)内未收到确认消息,那么对应的数据包就被假设为[已丢失](https://zh.wikipedia.org/wiki/丢包)并进行重传。
+当发送方发送数据之后,它启动一个定时器,等待目的端确认收到这个报文段。接收端实体对已成功收到的包发回一个相应的确认信息(ACK)。如果发送端实体在合理的往返时延(RTT)内未收到确认消息,那么对应的数据包就被假设为已丢失并进行重传。
- RTT(Round Trip Time):往返时间,也就是数据包从发出去到收到对应 ACK 的时间。
- RTO(Retransmission Time Out):重传超时时间,即从数据发送时刻算起,超过这个时间便执行重传。
RTO 的确定是一个关键问题,因为它直接影响到 TCP 的性能和效率。如果 RTO 设置得太小,会导致不必要的重传,增加网络负担;如果 RTO 设置得太大,会导致数据传输的延迟,降低吞吐量。因此,RTO 应该根据网络的实际状况,动态地进行调整。
-RTT 的值会随着网络的波动而变化,所以 TCP 不能直接使用 RTT 作为 RTO。为了动态地调整 RTO,TCP 协议采用了一些算法,如加权移动平均(EWMA)算法,Karn 算法,Jacobson 算法等,这些算法都是根据往返时延(RTT)的测量和变化来估计 RTO 的值。
+RTT 的值会随着网络的波动而变化,所以 TCP 不能直接使用 RTT 作为 RTO。为了动态地调整 RTO,TCP 协议采用了一些算法,如加权移动平均(EWMA)算法、Karn 算法、Jacobson 算法等,这些算法都是根据往返时延(RTT)的测量和变化来估计 RTO 的值。
## 参考
1. 《计算机网络(第 7 版)》
2. 《图解 HTTP》
-3. [https://www.9tut.com/tcp-and-udp-tutorial](https://www.9tut.com/tcp-and-udp-tutorial)
-4. [https://github.com/wolverinn/Waking-Up/blob/master/Computer%20Network.md](https://github.com/wolverinn/Waking-Up/blob/master/Computer%20Network.md)
-5. TCP Flow Control—[https://www.brianstorti.com/tcp-flow-control/](https://www.brianstorti.com/tcp-flow-control/)
-6. TCP 流量控制(Flow Control):
-7. TCP 之滑动窗口原理 :
+3. TCP and UDP Tutorial:
+4. Computer Network:
+5. TCP Flow Control:
+6. TCP 流量控制(Flow Control):
+7. TCP 之滑动窗口原理:
diff --git a/docs/cs-basics/network/tcp-time-wait.md b/docs/cs-basics/network/tcp-time-wait.md
new file mode 100644
index 00000000000..a2caf125c7f
--- /dev/null
+++ b/docs/cs-basics/network/tcp-time-wait.md
@@ -0,0 +1,192 @@
+---
+title: TCP TIME_WAIT 详解:为什么要等、会不会出问题、能不能复用?
+description: 深入分析 TCP TIME_WAIT 状态的两个存在原因(最后 ACK 补救机会 + 防旧包混入新连接),大量 TIME_WAIT 的危害边界与粗略估算,tcp_tw_reuse 的正确使用姿势,以及 TIME_WAIT 与 CLOSE_WAIT 的区分与线上排查思路。
+category: 计算机基础
+tag:
+ - 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: TCP,TIME_WAIT,CLOSE_WAIT,2MSL,tcp_tw_reuse,tcp_tw_recycle,四次挥手,端口耗尽,连接复用,MSL,PAWS
+---
+
+TCP 四次挥手的最后一步,主动关闭方发完 ACK 后不是立刻关闭,而是进入 `TIME_WAIT` 状态,默认要等上 60 秒。
+
+这 60 秒经常被误解:有人觉得是浪费资源,有人想着用内核参数强行关掉,有人把 `CLOSE_WAIT` 和 `TIME_WAIT` 混着排查。
+
+这篇文章回答线上最常见的几个问题:
+
+1. `TIME_WAIT` 到底在等什么?
+2. `TIME_WAIT` 大量堆积会不会真的出问题?
+3. `tcp_tw_reuse` 能不能随便开?
+4. `TIME_WAIT` 和 `CLOSE_WAIT` 怎么区分?
+
+## TIME_WAIT 不只是“等一会儿再关”
+
+ACK 都已经发出去了,为什么还要占着端口等几十秒?
+
+主动关闭方发出最后一个 ACK 后,不会立刻释放连接,而是进入 `TIME_WAIT`。RFC 9293 的连接状态图里也能看到,`TIME_WAIT` 会在 2MSL 超时后删除 TCB,并进入 `CLOSED`。
+
+这里要注意一个细节:不是“谁收到 FIN 谁就一定进入 TIME_WAIT”。被动关闭方收到 FIN 后,通常会先进入 `CLOSE_WAIT`,等待本端应用处理完剩余数据并调用 `close()` 或 `shutdown()`。更常见的情况是,主动关闭方收到对端最后的 FIN,并回复最后一个 ACK 后,进入 `TIME_WAIT`。
+
+**谁主动关闭连接,谁就更容易进入 TIME_WAIT。** 比如客户端主动断开 HTTP 短连接,`TIME_WAIT` 往往出现在客户端;如果服务端主动断开连接,服务端也可能堆出大量 `TIME_WAIT`。
+
+看起来像是多等了一会儿,实际上是在解决两个问题。
+
+## 第一个原因:让最后一个 ACK 有补救机会
+
+主动关闭方发送最后一个 ACK 后,如果这个 ACK 在网络中丢了,被动关闭方会以为自己的 FIN 没被确认,于是重发 FIN。主动关闭方还在 `TIME_WAIT` 里,就能再次回复 ACK;如果它已经进入 `CLOSED`,就可能回 RST,让对端感知为异常关闭或连接被重置。
+
+```mermaid
+sequenceDiagram
+ participant A as 主动关闭方
+ participant B as 被动关闭方
+
+ B->>A: FIN
+ A-->>B: ACK 丢失
+ Note over A: A 进入 TIME_WAIT 没有立刻释放连接
+ B->>A: 重传 FIN
+ A-->>B: 再次 ACK
+ Note over B: B 收到 ACK 后进入 CLOSED
+```
+
+**MSL(Maximum Segment Lifetime)** 是报文段在网络中的最大生存时间。2MSL 不是一次请求-响应的最大 RTT,而是一个保守等待窗口:既给最后 ACK 丢失后的 FIN 重传留出处理机会,也尽量保证旧连接中的延迟报文从网络中消失。
+
+需要注意,RFC 里的 MSL 是协议层概念,具体系统实现可能不同。Linux 常见实现中,`TIME_WAIT` 保留时间通常是 60 秒。还有一个常见误区:`tcp_fin_timeout` 控制的是 orphaned connection 的 `FIN_WAIT_2` 超时,不是 `TIME_WAIT`。想缓解 `TIME_WAIT` 带来的端口压力,优先看连接复用、端口范围、主动关闭方和 `tcp_tw_reuse` 条件,而不是试图用 `tcp_fin_timeout` 缩短 `TIME_WAIT`。
+
+## 第二个原因:别让旧连接的包混进新连接
+
+TCP 连接靠四元组定位:源 IP、源端口、目的 IP、目的端口。如果旧连接刚关闭,立刻用同一个四元组建立新连接,旧连接里延迟到达的数据包可能刚好落在新连接接收窗口里,被当成新连接的数据处理。
+
+举个例子:
+
+```text
+旧连接:client:50000 -> server:443
+服务端发出的 SEQ=301 数据包在网络里绕了一圈,迟迟没到。
+
+旧连接关闭后,客户端很快复用了同一个源端口:
+新连接:client:50000 -> server:443
+
+这时旧的 SEQ=301 抵达客户端。
+如果它刚好落在新连接接收窗口里,就有可能被误收。
+```
+
+TCP 序列号空间是 0 到 2^32 - 1,会按模 2^32 回绕,所以不能只靠序列号永久区分新老报文。实际系统还有时间戳、PAWS(Protection Against Wrapped Sequences)、随机 ISN 等保护,但它们不是“完全替代 TIME_WAIT”的万能方案。RFC 1337 也讨论过旧重复报文导致的 TIME_WAIT 风险。
+
+## 大量 TIME_WAIT 到底有没有问题?
+
+`TIME_WAIT` 本身是正常状态。真正的问题通常出现在主动关闭方短时间内创建大量到同一个目标 IP + 目标端口的连接,导致本地临时端口被占住。
+
+Linux 本地临时端口范围可通过 `net.ipv4.ip_local_port_range` 查看和调整。上游内核文档里的默认范围是 `32768 60999`,实际环境以本机输出为准:
+
+```bash
+cat /proc/sys/net/ipv4/ip_local_port_range
+```
+
+如果客户端短时间内反复连接同一个目标 IP + 目标端口,旧连接又都停在 `TIME_WAIT`,本地可用临时端口可能被占满,导致新连接无法分配源端口,常见报错如:
+
+```text
+Cannot assign requested address
+```
+
+可以按这个思路判断:
+
+- **如果服务端上看到很多 TIME_WAIT**:先看是不是服务端主动关闭了连接,比如服务端主动断开短连接、网关主动关闭上游连接、连接池主动淘汰连接。
+- **如果客户端或网关上看到很多 TIME_WAIT**:重点看是否存在短连接风暴、连接池未复用、HTTP keep-alive 没打开、上游频繁断连。
+
+还可以做一个粗略估算:
+
+```text
+同一目标 IP:Port 的短连接上限 ≈ 可用临时端口数 / TIME_WAIT 保留时间
+```
+
+比如默认端口范围 `32768~60999`,大约 2.8 万个端口。如果 `TIME_WAIT` 保留约 60 秒,那么同一目标 IP:Port 上持续新建短连接的上限大约是数百 QPS 量级。实际结果还会受到连接复用、端口保留、NAT、内核策略和不同远端四元组复用规则影响,不能只看 `TIME_WAIT` 总数就下结论。
+
+## 为什么不建议随便开 tcp_tw_reuse?
+
+`tcp_tw_reuse` 允许在协议认为安全的条件下,为新的主动连接复用 `TIME_WAIT` socket。它看起来像是缓解端口压力的捷径,但这类参数改变的是 TCP 对旧连接报文的等待策略,不能当成通用开关。
+
+这里要分三层看:
+
+1. **它依赖时间戳等条件判断“新报文是否足够新”**。时间戳可以过滤一部分旧报文,但不是所有异常都能覆盖。RFC 1337 重点讨论过 `TIME_WAIT` 状态被旧 RST 等报文提前终止的风险。旧数据段如果落入新连接可接受窗口,可能造成新旧数据混淆;旧 ACK 的影响则依赖序列号、窗口和实现细节,不宜和旧 RST 直接并列成同一种断连风险。
+2. **当前上游 Linux 文档中,`tcp_tw_reuse` 可取 0/1/2,默认值为 2**,表示仅允许 loopback 流量复用;`1` 才是全局开启。但旧版内核文档、发行版 man page 或历史资料可能仍写作“默认关闭”,实际机器必须以 `sysctl net.ipv4.tcp_tw_reuse` 为准。内核文档也明确提示,不要在没有专家建议或明确需求时修改。
+3. **不要把 `tcp_tw_reuse` 和已经废弃的 `tcp_tw_recycle` 搞混**。`tcp_tw_recycle` 在 NAT 环境下会导致时间戳冲突,大量连接被异常丢弃,Linux 4.12 之后已经被移除。网上很多老文章仍然会建议同时打开 `tcp_tw_reuse` 和 `tcp_tw_recycle`,这类配置不要照搬。
+
+一句话:`tcp_tw_reuse` 可以讨论,但必须结合 Linux 版本、是否 loopback、是否经过 NAT、是否启用时间戳、是否真的存在端口耗尽来判断。能在应用层解决的,优先在应用层解决。
+
+## TIME_WAIT 和 CLOSE_WAIT:一个正常等待,一个更像应用没收尾
+
+排查连接状态时,`CLOSE_WAIT` 通常比 `TIME_WAIT` 更值得警惕。
+
+收到对端 FIN 后,本端内核会回 ACK,然后进入 `CLOSE_WAIT`,等待应用处理完剩余数据并调用 `close()` 或 `shutdown()`。在 Java 服务里,`CLOSE_WAIT` 堆积经常和连接没有正确关闭有关。比如手写 Socket、HTTP 客户端响应体没有 close、异常分支提前 return、连接池连接没有归还,都可能让内核已经 ACK 了对端 FIN,但应用迟迟不调用 close。
+
+可以先按这个思路判断:
+
+- **TIME_WAIT**:主动关闭方在等 2MSL,通常是协议设计的一部分。
+- **CLOSE_WAIT**:被动关闭方已经知道对端不发了,但本端应用还没关闭 socket。大量堆积时,优先怀疑应用代码没释放连接、线程卡住、连接池归还异常、读写流程没有走到 finally。
+
+| 状态 | 常见出现方 | 含义 | 排查方向 |
+| ---------- | ---------- | ----------------------------------- | ------------------------------------------------- |
+| TIME_WAIT | 主动关闭方 | 等最后 ACK 重传机会,也等旧报文消失 | 短连接、连接池、keep-alive、端口范围 |
+| CLOSE_WAIT | 被动关闭方 | 对端已关闭,本端应用还没 close | 代码是否释放 socket、线程是否卡住、连接池是否泄漏 |
+
+## 排查时别只盯着数量,要先看谁在主动关闭
+
+
+
+看到大量 `TIME_WAIT` 或 `CLOSE_WAIT`,可以先用下面几条命令定位方向:
+
+`ss` 是 Linux 上 `iproute2` 提供的命令,macOS 默认没有。如果你的开发环境是 macOS,可以用 `netstat` 和 `lsof` 替代。
+
+```bash
+# Linux:查看各 TCP 状态数量
+ss -ant | awk 'NR>1 {cnt[$1]++} END {for (s in cnt) print s, cnt[s]}'
+
+# macOS:查看各 TCP 状态数量
+netstat -anp tcp | awk '$1 ~ /^tcp/ {cnt[$NF]++} END {for (s in cnt) print s, cnt[s]}'
+
+# Linux:查看 TIME-WAIT 主要集中在哪些目标
+ss -ant state time-wait | awk 'NR>1 {print $5}' | sort | uniq -c | sort -nr | head
+
+# macOS:查看 TIME-WAIT 主要集中在哪些远端
+netstat -anp tcp | awk '$1 ~ /^tcp/ && $NF=="TIME_WAIT" {print $(NF-1)}' | sort | uniq -c | sort -nr | head
+
+# Linux:查看 CLOSE-WAIT 对应哪个进程(需要 sudo 才能看到进程信息)
+sudo ss -tanp state close-wait
+
+# macOS:查看 CLOSE-WAIT 对应哪个进程
+sudo lsof -nP -iTCP -sTCP:CLOSE_WAIT
+
+# Linux:查看监听 socket 的 accept queue 情况
+ss -ltn
+```
+
+
+
+命令背后的判断:
+
+- **TIME_WAIT 集中在某个远端服务**:检查是否短连接太多、HTTP 连接复用没生效、连接池配置过小、连接池被频繁销毁,或者对端频繁主动断开。
+- **CLOSE_WAIT 集中在某个本地进程**:优先查应用代码,尤其是异常分支有没有关闭响应体、socket 或连接对象。
+- **LISTEN socket 的 Recv-Q 长时间接近 Send-Q**:重点排查 accept queue 堆积,看看应用 accept 是否及时、线程池是否卡住、backlog 配置是否过小。
+- 如果是网关、代理、爬虫、压测客户端,`TIME_WAIT` 更常见;如果是 Java 服务端内部依赖调用泄漏,`CLOSE_WAIT` 更常见。
+
+## 克制的优化建议
+
+按优先级排查:
+
+1. **优先减少不必要的短连接**:开启 HTTP keep-alive,复用连接池。
+2. **确认谁在主动关闭连接**:服务端、客户端、网关、连接池都有可能成为主动关闭方。
+3. **检查应用侧资源释放**:尤其是 HTTP 响应体、Socket、数据库连接、连接池连接归还。
+4. **扩大本地端口范围**:在客户端短连接确实很高、且存在端口耗尽证据时,再考虑调整 `ip_local_port_range`。
+5. **最后才看内核参数**:`tcp_tw_reuse`、`tcp_abort_on_overflow`、`tcp_syncookies` 都要结合 Linux 版本、业务连接模型、是否经过 NAT、是否被攻击、是否有真实观测数据来判断,不建议直接照抄网上配置。
+
+`TIME_WAIT` 多,不一定是故障;`CLOSE_WAIT` 多,通常要先看代码。这两个状态看起来都像“连接没关干净”,但问题方向完全不同。
+
+## 参考
+
+- RFC 9293: Transmission Control Protocol (TCP):
+- RFC 1337: TIME-WAIT Assassination Hazards in TCP:
+- Linux 内核 ip-sysctl 文档:
+- SoByte - 为什么 TCP 需要 TIME_WAIT 状态:
+
+
diff --git a/docs/cs-basics/network/the-whole-process-of-accessing-web-pages.md b/docs/cs-basics/network/the-whole-process-of-accessing-web-pages.md
index c09c10e6ab8..69cdea6342a 100644
--- a/docs/cs-basics/network/the-whole-process-of-accessing-web-pages.md
+++ b/docs/cs-basics/network/the-whole-process-of-accessing-web-pages.md
@@ -1,79 +1,343 @@
---
-title: 访问网页的全过程(知识串联)
+title: 从输入 URL 到页面展示到底发生了什么?
+description: 串联从输入 URL 到页面渲染的完整链路,涵盖 DNS、TCP、HTTP、TLS、ARP、数据封装与浏览器渲染,助力面试与实践理解。
category: 计算机基础
tag:
- 计算机网络
+head:
+ - - meta
+ - name: keywords
+ content: 访问网页流程,DNS,TCP 建连,HTTP 请求,TLS 握手,ARP,资源加载,浏览器渲染,关闭连接
---
-开发岗中总是会考很多计算机网络的知识点,但如果让面试官只靠一道题,便涵盖最多的计网知识点,那可能就是 **网页浏览的全过程** 了。本篇文章将带大家从头到尾过一遍这道被考烂的面试题,必会!!!
+在浏览器地址栏输入 URL 到页面展示,背后会串起 DNS、TCP、TLS、HTTP、ARP、数据封装与浏览器渲染等多个环节。
-总的来说,网络通信模型可以用下图来表示,也就是大家只要熟记网络结构五层模型,按照这个体系,很多知识点都能顺出来了。访问网页的过程也是如此。
+这道题经常被用来考察计网整体理解,因为它能把应用层、传输层、网络层和链路层的知识点都串起来。只背单个协议容易断片,按访问网页的全过程走一遍,会清楚很多。
+
+这篇文章主要回答几个问题:
+
+1. 输入 URL 后,浏览器会先做哪些本地处理?
+2. DNS 解析域名的过程是怎样的?
+3. TCP 连接如何建立?如果用了 HTTPS,TLS 握手又做了什么?
+4. HTTP 请求和响应的交互流程是什么?
+5. 数据包从主机到服务器,经过了哪些层的封装和转发?
+6. 浏览器拿到 HTML 后,如何继续加载 CSS、JS、图片等资源并渲染页面?
+7. 页面加载完成后,连接会如何复用或关闭?
+
+总的来说,网络通信模型可以用下图来表示。访问网页的过程,就是数据从应用层逐层向下封装,经物理网络传输到对端,再逐层向上解封装的过程。

-开始之前,我们先简单过一遍完整流程:
+开始之前,先简单过一遍完整流程:
-1. 在浏览器中输入指定网页的 URL。
-2. 浏览器通过 DNS 协议,获取域名对应的 IP 地址。
-3. 浏览器根据 IP 地址和端口号,向目标服务器发起一个 TCP 连接请求。
-4. 浏览器在 TCP 连接上,向服务器发送一个 HTTP 请求报文,请求获取网页的内容。
-5. 服务器收到 HTTP 请求报文后,处理请求,并返回 HTTP 响应报文给浏览器。
-6. 浏览器收到 HTTP 响应报文后,解析响应体中的 HTML 代码,渲染网页的结构和样式,同时根据 HTML 中的其他资源的 URL(如图片、CSS、JS 等),再次发起 HTTP 请求,获取这些资源的内容,直到网页完全加载显示。
-7. 浏览器在不需要和服务器通信时,可以主动关闭 TCP 连接,或者等待服务器的关闭请求。
+1. **浏览器解析 URL 并检查缓存**:浏览器解析 URL 的各组成部分,并检查 HTTP 缓存(强缓存、协商缓存)是否已有该资源的有效副本。
+2. **DNS 解析**:浏览器通过 DNS 协议,获取域名对应的 IP 地址。
+3. **建立 TCP 连接**:浏览器根据 IP 地址和端口号,向目标服务器发起 TCP 三次握手,建立可靠传输通道。
+4. **TLS 握手(HTTPS)**:如果使用 HTTPS,在 TCP 连接建立后还要进行 TLS 握手,协商加密密钥并验证服务器身份。
+5. **发送 HTTP 请求**:浏览器在连接上向服务器发送 HTTP 请求报文,请求获取网页内容。
+6. **服务器处理并返回响应**:服务器收到请求后处理并返回 HTTP 响应报文。
+7. **浏览器解析与渲染**:浏览器解析 HTML、CSS,执行 JavaScript,并加载页面中引用的其他资源(图片、字体等)。
+8. **连接管理**:页面加载完成后,连接根据 keep-alive 策略复用或关闭。
-## 应用层
+下面按这个流程逐一展开。
-一切的开始——打开浏览器,在地址栏输入 URL,回车确认。那么,什么是 URL?访问 URL 有什么用?
+## 第一步:解析 URL 与检查缓存
-### URL
+打开浏览器,在地址栏输入 URL 并回车。浏览器做的第一件事不是发请求,而是解析 URL 并检查是否可以直接使用本地缓存。
-URL(Uniform Resource Locators),即统一资源定位器。网络上的所有资源都靠 URL 来定位,每一个文件就对应着一个 URL,就像是路径地址。理论上,文件资源和 URL 一一对应。实际上也有例外,比如某些 URL 指向的文件已经被重定位到另一个位置,这样就有多个 URL 指向同一个文件。
+### URL 是什么
+
+URL(Uniform Resource Locator,统一资源定位符)是互联网上资源的唯一地址。网络上的每个可访问资源都对应一个 URL,理论上文件和 URL 一一对应。实际上也有例外,比如重定向或 CDN 场景下,多个 URL 可能指向同一份资源。
### URL 的组成结构

-1. 协议。URL 的前缀通常表示了该网址采用了何种应用层协议,通常有两种——HTTP 和 HTTPS。当然也有一些不太常见的前缀头,比如文件传输时用到的`ftp:`。
-2. 域名。域名便是访问网址的通用名,这里也有可能是网址的 IP 地址,域名可以理解为 IP 地址的可读版本,毕竟绝大部分人都不会选择记住一个网址的 IP 地址。
-3. 端口。如果指明了访问网址的端口的话,端口会紧跟在域名后面,并用一个冒号隔开。
-4. 资源路径。域名(端口)后紧跟的就是资源路径,从第一个`/`开始,表示从服务器上根目录开始进行索引到的文件路径,上图中要访问的文件就是服务器根目录下`/path/to/myfile.html`。早先的设计是该文件通常物理存储于服务器主机上,但现在随着网络技术的进步,该文件不一定会物理存储在服务器主机上,有可能存放在云上,而文件路径也有可能是虚拟的(遵循某种规则)。
-5. 参数。参数是浏览器在向服务器提交请求时,在 URL 中附带的参数。服务器解析请求时,会提取这些参数。参数采用键值对的形式`key=value`,每一个键值对使用`&`隔开。参数的具体含义和请求操作的具体方法有关。
-6. 锚点。锚点顾名思义,是在要访问的页面上的一个锚。要访问的页面大部分都多于一页,如果指定了锚点,那么在客户端显示该网页是就会定位到锚点处,相当于一个小书签。值得一提的是,在 URL 中,锚点以`#`开头,并且**不会**作为请求的一部分发送给服务端。
+一个完整的 URL 由以下几部分组成:
+
+1. **协议**(Scheme):URL 的前缀表示采用的协议,最常见的是 `http` 和 `https`,也有文件传输的 `ftp:` 等。
+2. **域名**(Host):访问目标的通用名,也可以直接使用 IP 地址。域名本质上是 IP 地址的可读版本。
+3. **端口**(Port):紧跟域名后面,用冒号隔开。HTTP 默认 80,HTTPS 默认 443,如果使用默认端口可以省略。
+4. **资源路径**(Path):从第一个 `/` 开始,表示服务器上的资源位置。早期设计中路径对应服务器上的物理文件,现在通常是后端路由映射的虚拟路径。
+5. **查询参数**(Query):`?` 之后的部分,采用 `key=value` 键值对形式,多个参数用 `&` 隔开。服务器解析请求时会提取这些参数。
+6. **锚点**(Fragment):`#` 之后的部分,用于定位到页面内的某个位置。锚点**不会**作为请求的一部分发送给服务端,仅由浏览器本地处理。
+
+### 浏览器缓存检查
+
+解析完 URL 之后,浏览器会先检查 HTTP 缓存,看是否已经有该资源的有效副本:
+
+1. **强缓存**:检查 `Cache-Control`(如 `max-age`)或 `Expires` 头,判断缓存是否仍在有效期内。如果有效,直接使用缓存,跳过后续所有网络请求。
+2. **协商缓存**:强缓存未命中时,浏览器向服务器发送验证请求(携带 `If-Modified-Since` 或 `If-None-Match`),服务器判断资源是否变化。如果未变化,返回 `304 Not Modified`,浏览器继续使用本地缓存;如果已变化,返回 `200 OK` 和新资源。
+
+HTTP 缓存命中时,整个访问过程在此结束,无需发起网络请求。
+
+### 域名解析准备
+
+如果 HTTP 缓存未命中,浏览器需要向服务器发起网络请求,首先要拿到域名对应的 IP 地址。在正式发起 DNS 查询之前,浏览器还会依次检查:
+
+1. **浏览器 DNS 缓存**:浏览器自身维护了一份 DNS 缓存,先看有没有该域名的记录。
+2. **操作系统 DNS 缓存**:浏览器缓存未命中时,查询操作系统的 DNS 缓存。
+3. **hosts 文件**:操作系统会检查本地 `hosts` 文件,看是否有域名到 IP 地址的直接映射。如果有,直接使用该 IP 地址,跳过 DNS 解析。
+
+如果以上都没有命中,浏览器就需要发起完整的 DNS 查询。
+
+## 第二步:DNS 解析
+
+DNS(Domain Name System,域名系统)要解决的是**域名和 IP 地址的映射问题**。域名只是便于人类记忆的名字,网络通信真正需要的是 IP 地址。
+
+### DNS 解析过程
+
+浏览器拿到域名后,DNS 解析通常按以下步骤进行:
+
+1. **浏览器 DNS 缓存**:浏览器自身维护了一份 DNS 缓存,先检查缓存中是否有该域名的记录且未过期。
+2. **操作系统 DNS 缓存**:浏览器缓存未命中时,向操作系统发起 DNS 查询请求。操作系统也有自己的 DNS 缓存。
+3. **本地 DNS 服务器**:操作系统配置的本地 DNS 服务器(通常由 ISP 提供,或使用公共 DNS 如 `8.8.8.8`、`114.114.114.114`)。本地 DNS 服务器如果有缓存且未过期,直接返回结果。
+4. **递归/迭代查询**:本地 DNS 服务器缓存未命中时,它会代替客户端发起迭代查询——先问根 DNS 服务器,再问顶级域 DNS 服务器(如 `.com`),最后问权威 DNS 服务器,逐级获取目标 IP 地址。
+5. **返回结果并缓存**:本地 DNS 服务器拿到最终结果后返回给客户端,同时在本地缓存一份,供后续查询使用。
+
+下图展示了一个典型的 DNS 迭代查询过程:
+
+
+
+实际场景中,本地 DNS 服务器通常已经缓存了大量 TLD 服务器地址,多数查询不需要从根服务器开始,跳过根服务器直接查 TLD 的情况非常普遍。
+
+> 关于 DNS 的更多细节(DNS 服务器层级、递归/迭代查询的区别、DNS 记录类型、为什么通常用 UDP 等),可以参考 [DNS 域名系统详解(应用层)](https://javaguide.cn/cs-basics/network/dns.html) 这篇文章。
+
+## 第三步:建立 TCP 连接
+
+拿到目标服务器的 IP 地址后,浏览器需要与服务器建立一个可靠的传输通道。HTTP 基于 TCP 协议,所以在发送 HTTP 请求之前必须先完成 TCP 三次握手。
+
+### TCP 三次握手
+
+TCP 三次握手的目的是**同步双方的初始序列号**,并**确认双方的收发路径是可用的**。
+
+
+
+1. **第一次握手(SYN)**:客户端发送 SYN 报文段,携带自己的初始序列号 `seq=x`,进入 `SYN_SENT` 状态。
+2. **第二次握手(SYN+ACK)**:服务端收到后回复 SYN+ACK,携带自己的初始序列号 `seq=y`,确认号 `ack=x+1`,进入 `SYN_RCVD` 状态。
+3. **第三次握手(ACK)**:客户端收到后发送 ACK,确认号 `ack=y+1`,双方进入 `ESTABLISHED` 状态,连接建立完成。
+
+三次握手的设计不是为了「多走一次」,而是让双方都能确认:对方能收到自己的数据,自己也能收到对方的数据。两次握手做不到这一点——服务端在第二次握手后,还不知道客户端是否收到了自己的 SYN+ACK。
+
+> 关于三次握手的详细分析、半连接队列/全连接队列、SYN Flood 防护等内容,可以参考 [TCP 三次握手和四次挥手(传输层)](https://javaguide.cn/cs-basics/network/tcp-connection-and-disconnection.html)。
+
+### 如果是 HTTPS:TLS 握手
+
+如果 URL 的协议是 HTTPS,TCP 连接建立之后还要进行 TLS 握手。TLS 的核心目标是三个:**加密**(防窃听)、**认证**(防冒充)、**完整性校验**(防篡改)。
+
+TLS 握手大致流程(以 TLS 1.2 RSA 密钥交换为例):
+
+1. **Client Hello**:客户端发送支持的 TLS 版本、加密套件列表和一个随机数。
+2. **Server Hello**:服务端从中选择一个加密套件,返回自己的证书、另一个随机数。
+3. **密钥交换**:客户端验证服务端证书的合法性(通过 CA 签名验证),然后生成预主密钥(Pre-Master Secret),用服务端公钥加密后发送给服务端。双方根据预主密钥和之前交换的两个随机数,计算出对称加密的会话密钥。
+4. **完成**:双方用会话密钥加密通信,握手结束。
+
+需要注意的是,上述流程描述的是 TLS 1.2 中基于 RSA 的密钥交换方式。现代 HTTPS 主流采用的是 ECDHE 密钥交换(TLS 1.2 和 TLS 1.3 均支持),密钥材料不是直接用公钥加密传输的,而是通过椭圆曲线 Diffie-Hellman 交换各自生成,并且具备前向安全性(Forward Secrecy)——即使服务端私钥泄露,历史通信也不会被解密。TLS 1.3 进一步简化了握手流程,将往返次数从 2-RTT 减少到 1-RTT,并移除了 RSA 静态密钥交换等不安全的密码套件。
+
+TLS 握手完成后,后续的 HTTP 请求和响应都会使用协商好的对称密钥进行加密传输。HTTPS 的安全性来自 TLS 层,而不是 HTTP 协议本身的改变。
+
+> 关于 TLS 的加密原理(非对称加密、对称加密、数字签名、CA 证书)的详细分析,可以参考 [HTTP vs HTTPS(应用层)](https://javaguide.cn/cs-basics/network/http-vs-https.html)。关于 RSA 和 ECDHE 两种密钥交换方式的区别,可以参考 [HTTPS RSA vs ECDHE 握手过程](https://javaguide.cn/cs-basics/network/https-rsa-vs-ecdhe.html)。
+
+## 第四步:发送 HTTP 请求
+
+TCP 连接(以及可能的 TLS 通道)建立好之后,浏览器就可以发送 HTTP 请求了。
+
+### HTTP 请求报文结构
+
+一个典型的 HTTP/1.1 请求报文如下:
+
+```http
+GET /index.html HTTP/1.1
+Host: www.example.com
+User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
+Accept: text/html,application/xhtml+xml
+Accept-Encoding: gzip, deflate, br
+Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
+Connection: keep-alive
+Cookie: session_id=abc123
+```
+
+各部分含义:
+
+- **请求行**:`GET /index.html HTTP/1.1` —— 请求方法(GET)、资源路径(`/index.html`)、协议版本(HTTP/1.1)。
+- **Host 头**:指定目标主机名。这是 HTTP/1.1 的强制要求,因为同一台服务器(同一个 IP)可能通过虚拟主机托管多个网站。
+- **其他请求头**:`User-Agent`(客户端信息)、`Accept`(可接受的响应类型)、`Accept-Encoding`(支持的压缩方式)、`Cookie`(携带的状态信息)等。
+
+### 服务器处理请求
+
+服务器收到请求后,经过一系列处理生成响应:
+
+1. **接收请求**:Web 服务器(如 Nginx、Tomcat)接收并解析 HTTP 请求报文。
+2. **路由分发**:根据 URL 路径将请求路由到对应的后端处理逻辑(Controller、Servlet 等)。
+3. **业务处理**:执行具体的业务逻辑,可能涉及数据库查询、缓存读取、调用其他服务等。
+4. **构建响应**:将处理结果封装成 HTTP 响应报文。
+
+### HTTP 响应报文结构
+
+```http
+HTTP/1.1 200 OK
+Content-Type: text/html; charset=UTF-8
+Content-Encoding: gzip
+Content-Length: 1256
+Cache-Control: max-age=3600
+Set-Cookie: session_id=xyz789; Path=/
+
+
+
+...
+
+```
+
+各部分含义:
+
+- **状态行**:`HTTP/1.1 200 OK` —— 协议版本、状态码(200)、状态描述。
+- **响应头**:`Content-Type`(响应体类型)、`Content-Encoding`(压缩方式)、`Cache-Control`(缓存策略)、`Set-Cookie`(设置 Cookie)等。
+- **响应体**:请求的实际内容,如 HTML 文档、JSON 数据、图片二进制数据等。
+
+常见的状态码:
+
+| 状态码 | 类别 | 常见示例 |
+| ------ | ---------- | --------------------------------------------- |
+| 2xx | 成功 | 200 OK、206 Partial Content |
+| 3xx | 重定向 | 301 永久重定向、302 临时重定向、304 未修改 |
+| 4xx | 客户端错误 | 400 Bad Request、403 Forbidden、404 Not Found |
+| 5xx | 服务端错误 | 500 Internal Server Error、502 Bad Gateway |
+
+> 关于 HTTP 常见状态码的详细总结,可以参考 [HTTP 常见状态码总结(应用层)](https://javaguide.cn/cs-basics/network/http-status-codes.html)。
+
+## 第五步:数据包的封装与转发
+
+HTTP 请求从浏览器发出后,数据并不是直接「飞」到服务器的。它需要经过协议栈的逐层封装,在物理网络上一跳一跳地转发到目的地。
+
+### 数据封装过程
+
+应用层的 HTTP 报文,经过传输层、网络层、链路层的逐层封装,最终变成能在物理介质上传输的比特流:
+
+
+
+每一层只关心自己要添加的头部信息,并使用下层提供的服务来传输数据:
+
+- **传输层(TCP)**:添加源端口和目的端口,用序列号和确认号保证可靠传输。
+- **网络层(IP)**:添加源 IP 和目的 IP,负责寻址和路由,决定数据包从源到目的经过的路径。
+- **链路层**:添加源 MAC 和目的 MAC 地址,负责在相邻节点之间传输数据帧。
+
+### 网络层的路由转发
+
+数据包从源主机到目的主机,通常需要经过多个路由器中转。网络层的核心功能就是**路由与转发**:
+
+- **路由**:确定分组从源到目的经过的路径(由路由协议如 OSPF、BGP 等计算)。
+- **转发**:将分组从路由器的输入端口转移到合适的输出端口。
+
+每个路由器维护一张路由表,根据目的 IP 地址查表决定下一跳。数据包在网络中就像快递包裹,每一站只看「下一站发到哪里」,不用关心全程路径。
+
+### ARP 协议:从 IP 地址到 MAC 地址
+
+数据帧在链路层传输时,需要知道下一跳设备的 MAC 地址,而不能只用 IP 地址。ARP(Address Resolution Protocol,地址解析协议)就是解决「已知 IP 地址,如何获取对应 MAC 地址」的问题。
+
+ARP 的工作方式是**广播问询、单播响应**:
+
+1. 主机先查本地 ARP 缓存表,看是否已有目标 IP 对应的 MAC 地址。
+2. 缓存未命中时,在局域网内广播一个 ARP 请求:「谁的 IP 是 xxx.xxx.xxx.xxx?请告诉我你的 MAC地址。」
+3. 目标设备(或路由器接口)收到后,以单播方式回复自己的 MAC 地址。
+4. 请求方收到响应后,将 IP-MAC 映射存入 ARP 缓存表,后续通信直接使用。
+
+如果目标主机不在同一子网,主机不需要知道最终目标的 MAC 地址,只需要知道**本地网关(路由器)的 MAC 地址**即可。数据包先发给网关,网关再逐跳转发到目标网络。
+
+> 关于 ARP 的详细工作原理(同子网/跨子网寻址、ARP 表、常见攻击),可以参考 [ARP 协议详解(网络层)](https://javaguide.cn/cs-basics/network/arp.html)。
+
+### 网络地址转换(NAT)
+
+在大多数家庭和企业网络中,内网主机使用的是私有 IP 地址(如 `192.168.x.x`),不能直接在公网上路由。NAT(Network Address Translation)协议负责在内网和公网之间转换 IP 地址。
+
+当内网主机发送数据包到公网时,NAT 设备(通常是路由器)会将源 IP 地址从私有地址替换为公网地址,并记录端口映射关系。响应数据包返回时,NAT 再根据映射表把目的地址转换回内网主机的私有地址。
+
+## 第六步:浏览器解析与渲染
+
+服务器返回 HTML 响应后,浏览器的工作才真正开始。浏览器需要解析 HTML、构建 DOM 树、加载子资源、计算样式、布局并最终渲染到屏幕上。
+
+### HTML 解析与 DOM 构建
+
+浏览器拿到 HTML 文档后,从上到下逐行解析:
+
+1. **构建 DOM 树**:解析 HTML 标签,生成文档对象模型(DOM)树,表示页面的结构。
+2. **构建 CSSOM 树**:遇到 ` ` 引用的 CSS 文件或 `