计算机网络面试
计算机网络面试
如果你不是从事于通信领域,面试时问及计算机网络的知识,一般也就限定在:HTTP(含 HTTPS、Cookie、Session)、TCP、UDP、Socket 这些
综合
【简单】计算机网络如何分层?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / 网络分层
💎 关键结论
计算机网络分层有 OSI 七层、TCP/IP 分层和五层协议三种体系,其中五层协议在教学与面试中最流行。自下而上为:物理层(比特流)、数据链路层(帧)、网络层(IP 数据报)、传输层(报文段)、应用层(报文),每一层为上层提供服务、屏蔽下层实现细节。
⚡记忆卡片
- 口诀:物联网传应,比特帧包段报文
- 关键词:OSI 七层 / 五层协议 / TCP/IP / 封装与解封装
- 链路:应用层 → 传输层 → 网络层 → 数据链路层 → 物理层
📖 核心知识

计算机网络分层一般有三种划分体系:OSI 分层;五层协议分层;TCP/IP 协议分层。
- OSI 的七层体系结构概念清楚,理论完整,但是比较复杂且不实用,所以并不流行。
- 五层协议分层是一种折中方案,在现实中更为流行。
物理层
物理层(Physical Layer)负责在物理介质上传输原始比特流(0 和 1)。它定义了设备的电气、机械、功能和规程特性,如电压、线速、线缆、接口、光缆等。
- 要点:调制、解调、数字信号、模拟信号、通信媒介、信道复用
- 数据单元:比特流
- 关键协议/标准:
- RS-232、V.35:古老的串行通信标准。
- IEEE 802.3:以太网的相关物理层标准(如 100BASE-TX)。
- T1/E1、SONET/SDH:电信级传输标准。
- 主要设备:光纤、同轴电缆、双绞线、中继器和集线器。
- 集线器 (Hub):傻瓜式设备,单纯地放大和转发电信号到所有端口。
- 中继器 (Repeater):用于放大信号,延长网络传输距离。
- 调制解调器 (Modem):在数字信号和模拟信号之间进行转换。
- 光纤、同轴电缆
数据链路层
数据链路层(Data Link Layer)负责在同一局域网内的节点之间可靠地传输数据帧。
- 要点:点对点信道、广播信道、局域网、以太网、MAC、适配器
- 帧同步:将比特流组装成帧,标明帧的开始和结束。
- 差错控制:通过 CRC(循环冗余校验)检测物理层产生的比特错误。
- 寻址:使用** MAC 地址**(物理地址)来唯一标识网络设备。
- 流量控制:控制发送速率,防止高速发送方淹没低速接收方。
- 数据单元:帧(frame)
- 关键协议
- 以太网 (Ethernet):目前最主流的局域网技术。
- PPP:点对点协议,常用于拨号上网。
- VLAN (虚拟局域网):在二层交换机上划分逻辑网络。
- CSMA/CD
- 主要设备
- 交换机 (Switch):智能设备,根据目标 MAC 地址将帧转发到特定的端口。
- 网桥 (Bridge):连接两个相似的局域网,现已基本被交换机取代。
网络层
网络层(network layer)负责在不同网络之间(网际互连)进行逻辑寻址和分组路由。
- 要点
- 逻辑寻址:使用** IP 地址**来标识设备和网络。
- 路由选择:根据网络状况,为数据包选择最佳路径。
- 分组与重组:将传输层的数据段封装成数据包。
- 数据单元:IP 数据报(packet)
- 关键协议:
- IP (Internet Protocol):核心协议,负责寻址和路由。
- ICMP:用于网络连通性测试和错误报告,如
ping、tracert。 - ARP:将 IP 地址解析为 MAC 地址。
- RIP, OSPF, BGP:动态路由协议。
- 主要设备
- 路由器 (Router):连接不同网络,根据 IP 地址为数据包选择路由。
传输层
传输层(transport layer)负责端到端的通信,为运行在不同主机上的应用进程提供逻辑通信。
- 要点:滑动窗口、拥塞控制、三次握手
- 服务:提供可靠的(TCP)或不可靠的(UDP)数据传输服务。
- 复用与分用:多个应用进程可以同时使用同一传输层服务。
- 差错控制与流量控制:确保数据完整、有序、不丢失地到达。
- 数据单元:报文段(segment)或用户数据报
- 关键协议
- TCP (传输控制协议):面向连接的、可靠的、基于字节流的协议。
- UDP (用户数据报协议):无连接的、尽最大努力交付的协议,效率高。
- 主要设备:
- 防火墙 (Firewall):工作在三、四层(甚至更高),可以根据 IP 和端口进行访问控制。
- 多层交换机:除了二层交换功能,还具备基于 IP 地址的三层路由功能。
会话层
会话层(Session Layer)不参与具体的传输,它提供包括访问验证和会话管理在内的建立和维护应用之间通信的机制。
表示层
表示层(Presentation Layer)是为在应用过程之间传送的信息提供表示方法的服务,它关心的只是发出信息的语法与语义。表示层要完成某些特定的功能,主要有不同数据编码格式的转换,提供数据压缩、解压缩服务,对数据进行加密、解密。
应用层
应用层(application layer)为应用程序提供网络服务接口,是用户与网络的交互界面。
- 数据单元:报文(message)
- 关键协议
- HTTP/HTTPS:万维网数据传送协议。
- FTP:文件传输协议。
- SMTP/POP3/IMAP:电子邮件相关协议。
- DNS:域名系统,将域名解析为 IP 地址。
- DHCP:动态主机配置协议,自动分配 IP 地址。
- WebSocket:全双工通信协议。
- 主要设备:
- 应用网关/代理服务器:工作在应用层,可以对特定应用协议的数据进行解析和控制。
🔬 扩展知识
详情
- 【L3】TCP/IP 体系中并没有独立的会话层与表示层,其功能(会话管理、编码转换、加密解密)被并入应用层协议实现,如 TLS 承担了加密与表示的部分职责。
- 【L4】分层架构的核心是封装与解封装:数据自上而下每经过一层就加上该层头部,对端收到后自下而上逐层剥除并解析头部,这正是
ping、tracert等工具能分层定位问题的基础。
🔀 发散问题
- Q:为什么分层有利于排障? → 各层职责独立,可以逐层定位:先看 DNS 解析(应用层)、再看 TCP 连接(传输层)、最后看 HTTP 响应内容,问题被隔离在单一层次内。
- Q:交换机和路由器分别工作在哪一层? → 交换机工作在数据链路层,根据 MAC 地址转发帧;路由器工作在网络层,根据 IP 地址为数据包选择路由。
【困难】从输入网址到网页显示,期间发生了什么?⭐⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:15 min | 🏷 标签:计算机网络 / 综合
💎 关键结论
先通过 DNS 找到 IP,再通过 TCP 建立连接,接着通过 TLS 保证安全,最后通过 HTTP 传输页面数据,浏览器最终解析渲染呈现给用户。 整个过程完美体现了网络分层模型的协同工作。
⚡记忆卡片
- 口诀:解析问路,握手接通,加密通话,请求收货,拆包渲染
- 关键词:DNS / 三次握手 / TLS / HTTP / 解析渲染
- 链路:DNS 解析 → TCP 三次握手 → TLS 握手 → HTTP 请求/响应 → 浏览器解析渲染 → TCP 四次挥手
📖 核心知识
核心流程
- DNS 解析:浏览器查询域名对应的 IP 地址(问路)。
- TCP 握手:与目标 IP 的服务器进行 三次握手,建立可靠连接(拨号接通)。
- TLS 握手(如为 HTTPS):协商加密密钥,建立安全通道(切换加密线路)。
- 发送 HTTP 请求:发出
GET /index.html等请求报文(说出需求)。 - 接收 HTTP 响应:服务器返回
200 OK和网页数据(收到包裹)。 - 解析渲染:浏览器解析 HTML/CSS/JS,渲染显示页面(拆包组装货物)。
- 加载资源:对页面中的图片、样式等资源重复步骤 2-5(获取所有零件)。
- TCP 挥手:页面加载完成后,四次挥手释放连接(挂断电话)。
涉及的核心协议与角色
| 步骤 | 核心协议 | 核心角色 |
|---|---|---|
| 问地址 | DNS ( over UDP ) | DNS 服务器 |
| 建连接 | TCP | 浏览器、服务器 |
| 保安全 | TLS ( over TCP ) | 证书颁发机构 (CA) |
| 传内容 | HTTP/HTTPS ( over TCP ) | Web 服务器 (Nginx/Apache) |
🔬 扩展知识
详情
- 【L3】各阶段的量化开销:
| 阶段 | 典型耗时 | 说明 |
|---|---|---|
| DNS 解析 | 缓存命中约 0 ms;未命中 20~120 ms | 迭代查询最多经过根、顶级域、权威 3 级服务器 |
| TCP 握手 | 1 RTT(跨城约 10~50 ms) | Keep-Alive 连接复用后为 0 |
| TLS 握手 | TLS 1.2 约 2 RTT;TLS 1.3 仅 1 RTT,会话恢复支持 0-RTT | 0-RTT 数据有重放风险,仅适合幂等请求 |
| HTTP 请求/响应 | 取决于服务端处理 | TTFB(首字节时间)慢,八成是后端慢查询、GC、锁 |
| 资源加载 | 每资源 1 次请求 | HTTP/2 单连接多路复用,HTTP/1.1 浏览器对同域限 6 条连接 |
- 【L3】方案权衡:
| 方案 | 收益 | 适用边界 / 代价 |
|---|---|---|
DNS 预解析(dns-prefetch) | 省 1 次解析往返 | 仅对即将访问的第三方域名有意义,滥用浪费解析资源 |
| HTTP/2 多路复用 | 单连接承载全部请求,省多次握手 | 底层仍是 TCP,高丢包时一条流重传阻塞所有流 |
| TLS 1.3 + 会话恢复 | 建连从 2 RTT 降到 0~1 RTT | 0-RTT 需服务端做防重放;老旧中间设备可能干扰 |
| 强缓存 | 资源加载 0 网络开销 | 只对可指纹化的静态资源有效,动态接口无法使用 |
- 【L4】首次访问瓶颈在网络建连链路(DNS + TCP + TLS 合计 2~4 RTT);重复访问有连接复用和缓存,瓶颈转移到服务端处理时间与浏览器渲染(关键渲染路径、阻塞型 JS)。
🏭 实战场景
详情
- 踩坑案例:某次换 CDN 厂商后首页白屏时间翻倍。排查:Performance 面板显示 DNS 查询耗时 300 ms+,抓包确认本地 DNS 反复向境外权威服务器迭代查询。根因:新厂商的权威 DNS 在国内无节点,且旧缓存过期后全部回源。修复:接入国内权威 DNS + 页面加
dns-prefetch和preconnect,首屏恢复原速。 - 场景题:线上版本发布后,监控显示华南某运营商用户的页面 P95 加载时间从 1.2 s 涨到 5 s,其他地域正常,如何排查?
- 应急处理:先确认是否为 DNS/链路问题——用拨测平台对该运营商多节点测速,若 TTFB 正常而连接阶段慢,优先怀疑 DNS 或路由;必要时把静态资源切回旧 CDN 域名止血。
- 根因分析:把耗时拆成 DNS/TCP/TLS/TTFB/内容传输五段分别度量;发现该地域 DNS 解析被劫持到慢速递归,且新域名未配置预解析。用
dig +trace验证解析链路,用traceroute/mtr验证路由无异常,排除应用问题。 - 长期方案:域名启用 HSTS 防降级、接入多家权威 DNS 做容灾、页面配置
dns-prefetch,并把分段耗时埋点纳入发布门禁。 - 权衡:多 CDN 冗余能抗单运营商故障,但带来缓存命中率下降和调度复杂度,按业务对可用性的要求取舍。
⚠️ 常见误区
详情
- ❌ "用了 HTTPS,DNS 劫持就无所谓" → HTTPS 的证书校验能兜底识别假冒站点,但解析仍会指向错误 IP 造成访问失败或钓鱼诱导;HTTP 站点则完全失守。
- ❌ "建连失败一定是服务挂了" → 服务端半连接队列(backlog)满时 SYN 被丢弃,客户端只表现为握手超时重试,需要检查队列溢出计数而非只盯应用日志。
- ❌ "HTTP/2 多路复用一定更快" → 丢包率超过 2%~5% 的弱网下,单连接重传会阻塞所有流,多路复用反而被 TCP 队头阻塞拖累,需要 HTTP/3 解决。
- ❌ "TLS 0-RTT 可以放心开启" → 0-RTT 报文可被攻击者重放,重复触发非幂等操作(如重复下单),仅适合幂等请求。
🔀 发散问题
- Q:有了 HTTP/2 多路复用,为什么 TCP 三次握手仍省不掉? → 多路复用是应用层的并发能力,可靠性、有序交付和拥塞控制仍由 TCP 提供,第一条流建连前必须完成 1 RTT 握手。这也是 HTTP/3 换用 QUIC 把传输层与加密握手合并的动因。
- Q:TLS 1.3 的 0-RTT 为什么只建议用于幂等请求? → 0-RTT 数据在握手完成前就发出且无法保证不重复:握手失败重连时客户端可能重发,攻击者也可重放抓到的报文,非幂等操作会被执行两次。
- Q:首次访问和重复访问的耗时瓶颈分别在哪? → 首次访问瓶颈在网络建连链路(DNS + TCP + TLS);重复访问有连接复用和缓存,瓶颈转移到服务端处理时间与浏览器渲染。
HTTP
【中等】HTTP 1.0 和 2.0 有什么区别?⭐⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / HTTP 协议
💎 关键结论
HTTP/2 通过二进制帧、多路复用和头部压缩三大技术,从根本上解决了 HTTP/1.x 的性能瓶颈,大幅降低了延迟并节省了带宽,是 Web 性能的一次重大飞跃。
⚡记忆卡片
- 口诀:二进帧、多复用,头部压缩省带宽
- 关键词:二进制帧 / 多路复用 / HPACK / 服务器推送
- 链路:HTTP/1.x 文本短连接 → HTTP/2 二进制帧 → 多路复用 → HPACK 头部压缩
📖 核心知识
核心改进
| 对比维度 | HTTP/1.0 | HTTP/2.0 | 带来的好处 |
|---|---|---|---|
| 协议格式 | 纯文本 | 二进制帧 | 解析高效、错误少、紧凑 |
| 连接方式 | 短连接 (每次请求新建 TCP 连接) | 多路复用 (单连接并行处理无数请求) | 极大降低延迟,减少连接开销,解决应用层队头阻塞 |
| 头部传输 | 无压缩 (每次发送冗余头部) | HPACK 压缩 (静态表+动态表+哈夫曼编码) | 节省大量带宽 (减少 50%-90%头部大小) |
| 资源推送 | 被动响应 (需客户端先请求) | 服务器主动推送 (预测并推送相关资源) | 减少往返次数,提升页面加载速度 |
| 资源调度 | 优先级支持弱 | 原生流优先级 (设置权重和依赖) | 优化加载顺序,提升用户体验 |
对开发者的影响
- 语法不变:所有 HTTP 方法 (GET/POST)、状态码 (200/404)、URL 等概念完全保留。
- 无需改代码:性能提升在底层协议栈自动完成,应用层无感知。
- 必须 HTTPS:主流浏览器只支持在加密连接上使用 HTTP/2,推动了全网安全化。
🔬 扩展知识
详情
- 【L3】HTTP/2 一定比 HTTP/1.1 快吗?方案权衡:
| 场景 | 更优方案 | 原因 |
|---|---|---|
| 高延迟、低丢包、海量小请求 | HTTP/2 | 多路复用省掉多次握手,HPACK 压缩收益最大 |
| 丢包率 > 2%~5% 的弱网 | HTTP/1.1 多连接或 HTTP/3 | HTTP/2 单 TCP 连接,一个包丢失会阻塞所有流(队头阻塞从应用层转移到了传输层) |
| 超大文件下载 | HTTP/1.1 分片多线程下载 | 单连接的拥塞窗口上限低于多连接聚合带宽 |
| 头部高度重复的 API | HTTP/2 | HPACK 动态表命中后头部增量仅数字节 |
- 【L3】HTTP/2 多路复用只解决了应用层队头阻塞,队头阻塞转移到了 TCP 层:多个流共享一条 TCP 连接,任何一个包丢失触发重传,其后所有流的数据都被卡住,这正是 HTTP/3 诞生的动因。
- 【L4】内部微服务升级到 HTTP/2 时,多连接聚合的负载均衡模型会失效——gRPC 所有 RPC 复用一条连接,四层 LB 按连接数均衡会严重倾斜,需要按流/请求级别的七层均衡或客户端负载均衡。
🏭 实战场景
详情
- 踩坑案例:全站升级 HTTP/2 后,海外线路大文件下载的 P99 不升反降。排查:抓包发现单条 TCP 连接频繁重传,重传期间所有并行的下载流全部停等。根因:跨国链路丢包率约 4%,HTTP/2 把几十个下载流复用在一条连接上,TCP 队头阻塞被放大。修复:大文件下载域名单独回退 HTTP/1.1 多连接,其余保持 HTTP/2,并排期接入 HTTP/3。
- 场景题:团队把静态站点从 HTTP/1.1 升级到 HTTP/2,移动端弱网用户反馈页面反而更卡,如何分析并决策?
- 应急处理:先按网络质量分流——对探测丢包率高的客户端(或按 UA/运营商灰度)回退 HTTP/1.1,保住体验底线。
- 根因分析:HTTP/1.1 时代浏览器开 6 条连接,丢包只阻塞其中一条;HTTP/2 所有资源挤在一条 TCP 连接上,弱网下 4% 丢包即可让重传频繁发生,CSS/JS 等关键资源被非关键图片阻塞。用
netstat -s看重传计数、对比升级前后的 Performance 瀑布图即可定位。 - 长期方案:接入 HTTP/3(QUIC),从协议层消除传输层队头阻塞;过渡期可用资源优先级(流权重)让关键资源先走,并减少单页资源总数(合并、内联关键 CSS)。
- 权衡:HTTP/3 需要 UDP 443 放行,部分企业网络会屏蔽 UDP,必须保留 HTTP/2 回退链路,双协议并行运行一段时间。
⚠️ 常见误区
详情
- ❌ "HTTP/2 Server Push 是主流优化手段" → Chrome 106(2022 年)已移除 Server Push——推送与浏览器缓存竞争、浪费带宽,业界改用
103 Early Hints。 - ❌ "升级 HTTP/2 就一定提速" → 老旧负载均衡/防火墙不支持 HTTP/2 或强制剥离
Upgrade时,连接会静默退回 HTTP/1.1,优化效果归零。 - ❌ "HTTP/2 没有队头阻塞" → 只是应用层队头阻塞被解决,问题转移到了 TCP 层:一个包丢失会阻塞该连接上的所有流。
🔀 发散问题
- Q:HTTP/2 多路复用既然解决了应用层队头阻塞,为什么还需要 HTTP/3? → 队头阻塞只是从应用层转移到了 TCP 层,任何一个包丢失触发重传,其后所有流都被卡住;HTTP/3 用基于 UDP 的 QUIC 让每个流独立确认,丢包只影响单个流。
- Q:为什么主流浏览器要求 HTTP/2 必须跑在 HTTPS 上? → 协议本身允许明文 h2c,但历史上大量中间设备无法正确解析二进制帧会把连接弄坏;强制 ALPN + TLS 让中间设备"看不懂就透传",同时推动了全网安全化。
- Q:内部微服务调用升级到 HTTP/2 有什么额外注意点? → gRPC 所有 RPC 复用一条连接,四层 LB 按连接数均衡会严重倾斜,需要支持按流/请求级别的七层均衡或客户端负载均衡。
【中等】HTTP 2.0 和 3.0 有什么区别?⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / HTTP 协议
💎 关键结论
HTTP/3 通过将底层协议从 TCP 替换为 QUIC,彻底解决了延迟和连接稳定性的瓶颈,尤其在高丢包和移动网络环境下,性能提升显著。对于开发者而言,HTTP 的语法和 API 保持不变,所有优化都在底层自动完成。
⚡记忆卡片
- 口诀:三换 QUIC,流独立,零往返,断网不断连
- 关键词:QUIC / UDP / 0-RTT / 连接 ID / 连接迁移
- 链路:TCP + TLS(HTTP/2) → QUIC over UDP(HTTP/3) → 流独立确认 → 连接迁移
📖 核心知识
核心改进
| 对比维度 | HTTP/2 | HTTP/3 | 带来的好处 |
|---|---|---|---|
| 协议 | TCP + TLS (TCP 层丢失包会阻塞所有流) | QUIC (运行在 UDP 之上,丢包只影响单个流) | 高丢包网络下更稳定、更快速 |
| 连接速度 | 1-3 次往返 (首次握手) | 1 次往返 (首次),支持 0-RTT (重连) | 连接建立更快,重复访问速度极快 |
| 网络切换 | 连接会中断 (IP 变化导致 TCP 连接断裂) | 无缝连接 (通过连接 ID 标识,与 IP 无关) | Wi-Fi/5G 切换无感知,体验更流畅 |
| 安全与纠错 | 需 TLS 加密 | 默认加密,支持前向纠错 | 安全性更高,抗丢包能力更强 |
🔬 扩展知识
详情
- 【L3】QUIC 在 UDP 之上自实现了可靠传输:序号、ACK、重传、拥塞控制与流量控制全部重做,且按流独立确认,从而绕开了 TCP 的队头阻塞。
- 【L3】QUIC 把传输层握手与 TLS 加密握手合并,首次建连 1 RTT,重连借助会话恢复可到 0-RTT。
- 【L4】HTTP/3 依赖 UDP 443 端口,部分企业网络与中间设备会屏蔽或干扰 UDP,生产落地必须保留 HTTP/2 回退链路,双协议并行。
🔀 发散问题
- Q:HTTP/3 为什么在 Wi-Fi/5G 切换时不断连? → QUIC 用连接 ID 而非四元组标识连接,IP 变化不影响连接存续,实现连接迁移。
- Q:HTTP/3 落地有哪些代价? → 需要放行 UDP 443,部分中间设备会丢 UDP 包,必须保留 HTTP/2 回退并观测两种协议的实际表现再切量。
【中等】HTTP 和 HTTPS 有什么区别?⭐⭐⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / HTTPS
💎 关键结论
HTTPS = HTTP + 加密 + 身份认证 + 数据完整性保护,是 HTTP 的安全升级版,已成为现代网站的必备标准。
⚡记忆卡片
- 口诀:HTTPS 就是 HTTP 穿 TLS,加密认证防篡改
- 关键词:TLS / 证书 / 443 端口 / CA / 混合加密
- 链路:HTTP 明文 → TLS 握手 → 证书验身份 → 对称加密通信
📖 核心知识
核心差异
| 特性对比 | HTTP | HTTPS |
|---|---|---|
| 数据传输 | 明文,不安全 | 加密,防窃听、防篡改 |
| 身份认证 | 无,可能遇到假网站 | 有,通过 SSL 证书验证真身 |
| 默认端口 | 80 | 443 |
| 浏览器显示 | 网址前显示 “不安全” | 网址前显示 “锁”图标🔒 |
方案权衡
| 维度 | HTTP | HTTPS |
|---|---|---|
| 建连开销 | 无加密握手 | TLS 1.2 约 2 RTT,TLS 1.3 仅 1 RTT,会话恢复可到 0-RTT |
| CPU 开销 | 无 | 对称加密走 AES-NI 硬件指令,开销可忽略(< 1% CPU);瓶颈在 RSA 签名的握手阶段,ECDSA 证书或会话复用可缓解 |
| 运维成本 | 低 | 证书申请、续期、链完整性管理 |
| 适用边界 | 纯公开内容、内网调试 | 涉及账号、支付、隐私一律强制 HTTPS |
🔬 扩展知识
详情
- 【L3】HTTPS 加密了内容,但报文长度、时序、连接时长等元信息仍明文可见,攻击者可做流量分析推测用户行为;缓解手段包括 TLS 1.3 加密更多握手字段、ECH(Encrypted Client Hello)加密 SNI、填充报文长度。
- 【L3】零信任架构下内网微服务建议上 mTLS:内网横向渗透是真实威胁,mTLS 提供双向身份认证与传输加密,证书轮转通常交给服务网格(如 Istio)自动完成。
- 【L4】正确做法是 HSTS 强制 HTTPS、移动端证书固定(Certificate Pinning),证书校验失败直接拒绝,而不是依赖浏览器"继续访问"的兜底——点击继续等于放弃身份认证。
🏭 实战场景
详情
- 踩坑案例:证书自动续期上线后,某 App 渠道用户大面积报"无法建立安全连接",PC 浏览器正常。排查:用
openssl s_client -connect抓握手过程,发现服务端只下发了叶子证书。根因:续期脚本只替换了服务器证书文件,丢失了中间 CA 证书,iOS/Android 不会像桌面浏览器那样自动补链。修复:Nginx 证书文件合并为"叶子 + 中间证书"完整链,并在发布流程中加证书链完整性校验。 - 场景题:凌晨 0 点,公司主站 HTTPS 证书突然过期,全站用户浏览器报"连接不安全",如何处置?
- 应急处理:第一时间启用备用/紧急签发的证书(云厂商可分钟级签发),或临时切到上一版有效证书回滚;同时公告引导,避免客服端爆量。
- 根因分析:复盘发现证书续期任务静默失败(DNS 验证的 TXT 记录被清理脚本误删),且到期告警只发给了已离职员工的邮箱,无人跟进。
- 长期方案:接入 ACME 自动续期并保留失败重试与多渠道告警(到期前 30/7/1 天);用外部拨测持续校验证书有效期与链完整性;核心域名使用多年期证书或托管服务。
- 权衡:完全自动化续期减少人为失误,但依赖外部 CA 的可用性;自建私有 CA 可控性强,却要求所有客户端预置根证书,只适合纯内部系统。
⚠️ 常见误区
详情
- ❌ "证书部署好就一劳永逸" → 证书过期是最常见的生产事故之一,一夜之间全站不可访问,必须配置到期前 30 天告警并接入自动续期。
- ❌ "PC 浏览器显示正常,证书就没问题" → 证书链不完整时,部分移动端/老系统找不到中间 CA 验链失败,PC 端却能自动补链,极具迷惑性。
- ❌ "用户机器时间不准没影响" → 客户端时钟偏差会导致证书"未生效/已过期"误报,是证书类客诉的常见来源。
- ❌ "HTTPS 页面里嵌个 HTTP 资源没关系" → 混合内容会被浏览器直接拦截,页面样式/图片缺失。
- ❌ "关闭 TLS 1.0/1.1 无副作用" → 老旧 Android 客户端可能集体连不上,下线前需要提前灰度观测。
🔀 发散问题
- Q:HTTPS 加密了内容,攻击者还能通过什么方式推测用户行为? → 流量分析:报文长度、时序、连接时长都是明文可见的元信息,SNI 字段(TLS 1.2 及以前)直接暴露目标域名;缓解靠 TLS 1.3、ECH 与长度填充。
- Q:证书校验失败时浏览器允许"继续访问",生产系统能依赖这个兜底吗? → 不能。点击继续等于放弃身份认证,中间人可任意伪造站点窃取凭据;应使用 HSTS 与证书固定,校验失败直接拒绝。
- Q:内网微服务之间有必要上 mTLS 吗? → 零信任架构下有必要,mTLS 提供双向认证与加密;证书轮转运维成本交给服务网格自动化,性能损耗在硬件加速下可忽略。
【中等】HTTPS 的加密过程是怎样的?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / HTTPS
💎 关键结论
HTTPS 先通过非对称加密“安全地约定”一个密码本(会话密钥),之后双方就一直用这个密码本进行对称加密的“秘密通话”。核心智慧是:用非对称加密的安全性解决对称加密的密钥分发问题。
⚡记忆卡片
- 口诀:非对称换钥匙,对称传数据,证书证身份
- 关键词:混合加密 / 会话密钥 / 数字证书 / 三个随机数
- 链路:交换随机数 → 验证证书取公钥 → 协商预备主密钥 → 生成会话密钥 → 对称加密通信
📖 核心知识
核心思想:混合加密
- 非对称加密(RSA/ECC):用于安全握手,交换密钥。安全但慢。
- 对称加密(AES/ChaCha20):用于传输数据。快但需解决密钥分发问题。
- HTTPS 的智慧:用非对称加密的安全性来解决对称加密的密钥分发问题。
加密四步曲
打招呼与挑战:
- 客户端和服务器互相交换支持的技术参数和随机数,为生成密钥准备材料。
证书验证:
- 服务器出示由权威机构(CA)颁发的数字证书。
- 客户端验证证书真伪和有效性,并从中提取服务器公钥。
密钥协商
- 客户端生成一个预备主密钥,并用服务器公钥加密后发送。
- 服务器用自己唯一的私钥解密,得到该密钥。
- 此时,双方拥有了相同的三个随机数(Client Random, Server Random, Premaster Secret),据此独立计算出相同的会话主密钥。
加密通信:握手完成,后续所有数据传输都使用刚生成的会话密钥进行高效的对称加密/解密。
为什么这么做?
- 安全:非对称加密保证了密钥交换过程无法被窃听。
- 高效:对称加密保证了海量数据传输的速度。
- 身份认证:数字证书确保了你在和真正的目标服务器通信,而非中间人。
🔬 扩展知识
详情
- 【L3】现代 TLS 主流采用 ECDHE 类密钥交换,每次会话的密钥都与长期私钥解耦,即使私钥日后泄露也无法解密历史流量(前向安全)。
- 【L3】TLS 1.3 精简了握手流程并支持会话恢复的 0-RTT,但 0-RTT 数据有重放风险,仅适合幂等请求。
- 【L4】混合加密是"安全性与性能"的经典工程折中:非对称加密计算开销大,只用来保护少量关键材料;对称加密速度快,承担海量数据传输。
🔀 发散问题
- Q:为什么不全程使用非对称加密? → 非对称加密的计算开销远大于对称加密,无法支撑海量数据传输,只适合交换少量密钥材料。
- Q:数字证书在其中起什么作用? → 保证拿到的公钥确实属于目标服务器而非中间人;没有证书校验,非对称交换本身也会被中间人冒充。
【中等】HTTP 与 RPC 之间的区别?⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / HTTP 协议
💎 关键结论
- HTTP:一种具体的通信协议(如邮寄的“标准信封格式”)。
- RPC:一种通信概念/范式(“像调用本地函数一样调用远程服务”的理念),可以用 HTTP 或其他协议来实现。
- 一句话总结:对外(开放 API)用 HTTP,通用、标准、兼容性无敌;对内(微服务)用 RPC,高效、治理能力强、性能极致。
⚡记忆卡片
- 口诀:HTTP 是协议,RPC 是范式,对外 HTTP 对内 RPC
- 关键词:RESTful / gRPC / Protobuf / 服务治理
- 链路:远程方法调用 → 序列化编码 → 传输协议(TCP/HTTP/2) → 服务治理
📖 核心知识
核心对比
| 特性维度 | HTTP (常指 RESTful API) | RPC (如 gRPC, Dubbo) |
|---|---|---|
| 设计目标 | 通用资源操作(GET/POST/PUT/DELETE) | 远程方法调用 |
| 性能 | 文本传输(JSON/XML),性能相对较低 | 二进制编码(Protobuf 等),性能高 |
| 协议 | 标准 HTTP 协议 | 可基于 TCP 自定义协议,也可基于 HTTP/2 |
| 适用场景 | 对外开放 API,跨语言跨平台 | 内部微服务调用,追求高性能治理 |
| 服务治理 | 需依赖网关、Mesh 等外部组件 | 内置服务发现、熔断等治理能力 |
现代趋势:两者边界模糊,gRPC 等现代 RPC 框架直接基于** HTTP/2 **传输,兼顾了性能与通用性。
🔬 扩展知识
详情
- 【L3】gRPC 基于 HTTP/2 多路复用,所有 RPC 共享一条 TCP 连接:四层负载均衡按连接数分配会严重倾斜,需要七层均衡或客户端负载均衡。
- 【L3】RPC 框架的核心竞争力不在协议本身,而在内置的服务发现、负载均衡、熔断限流、超时重试等治理能力。
🔀 发散问题
- Q:gRPC 能直接对外提供 API 吗? → 技术上可以,但浏览器对原生 gRPC 支持有限,通常前面加一层网关转成 HTTP/JSON(如 gRPC-Web)。
- Q:基于 HTTP 的接口一定性能差吗? → 不一定。性能瓶颈更多在序列化格式与连接复用:HTTP/2 + 二进制编码(如 gRPC)同样基于 HTTP,性能与自定义 TCP 协议相当。
【中等】正向代理和反向代理有什么区别?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / 代理
💎 关键结论
- 正向代理(Forward Proxy):代理客户端。客户端配置代理,由代理替用户访问目标服务器,目标服务器只知道代理的 IP。
- 反向代理(Reverse Proxy):代理服务端。用户请求打到代理(如 Nginx),由代理转发到后端真实服务器,用户不知道后端是哪台机器。
- 一句话总结:正向代理隐藏了真实客户端,反向代理隐藏了真实服务端——代理的是谁,谁就是被隐藏的一方。
⚡记忆卡片
- 口诀:正代客户端,反代服务端;代理谁,就藏谁
- 关键词:正向代理 / 反向代理 / Nginx / 负载均衡
- 链路:客户端 → 代理服务器 → 目标/后端服务器
📖 核心知识
核心对比
| 对比维度 | 正向代理 | 反向代理 |
|---|---|---|
| 代理对象 | 客户端 | 服务端 |
| 感知方 | 服务端不知道真实客户端 | 客户端不知道真实后端 |
| 典型用途 | 翻墙、爬虫、匿名访问 | 负载均衡、缓存、SSL 卸载、限流 |
| 典型产品 | Squid、Shadowsocks | Nginx、HAProxy、网关 |
🔬 扩展知识
详情
- 【L3】正向代理必须由客户端显式配置才能生效,服务端无感知;反向代理对客户端完全透明,客户端只知道自己访问了一个域名。
- 【L3】反向代理是流量入口的核心组件:负载均衡、缓存加速、SSL 卸载、限流熔断等能力都挂在反向代理层实现。
🔀 发散问题
- Q:Nginx 算正向代理还是反向代理? → 生产中最常用作反向代理(流量入口 + 负载均衡),但也能配置为客户端使用的正向代理。
- Q:API 网关和反向代理是一回事吗? → 网关本质是增强版反向代理,在转发之外附加认证鉴权、限流、协议转换、灰度路由等能力。
【中等】WebSocket 的握手过程是怎样的?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / 应用层协议
💎 关键结论
WebSocket 是运行在 TCP 之上的全双工应用层协议,其握手采用HTTP 升级机制:一次带 Upgrade 头的 HTTP 请求,服务端回 101 Switching Protocols 后双方切换为全双工通信。目的是复用 HTTP 的端口(80/443)和基础设施,同时兼容代理和防火墙。
⚡记忆卡片
- 口诀:HTTP 升级问路,101 应答切换全双工
- 关键词:Upgrade / Sec-WebSocket-Key / 101 / 全双工 / 帧
- 链路:HTTP 请求(Upgrade: websocket) → 服务端 101 响应 → 切换 WebSocket 帧通信
📖 核心知识
握手流程
- 客户端发起一个特殊的 HTTP/1.1 请求,携带以下头部:
Upgrade: websocket、Connection: Upgrade:声明要升级协议。Sec-WebSocket-Key:客户端生成的随机 Base64 字符串。
- 服务端校验后返回
101 Switching Protocols响应,携带Sec-WebSocket-Accept(将 Key 与固定 GUID 拼接后做 SHA-1 + Base64 计算得出)。 - 客户端校验 Accept 值正确后,双方切换到 WebSocket 协议,此后通过**帧(frame)**进行全双工通信,连接长期保持。
为什么这样设计
Sec-WebSocket-Key/Accept不用于安全加密,只是确认双方都理解 WebSocket 协议、防止被普通 HTTP 服务器误处理。- 借用 HTTP 握手可以天然穿透只放行 80/443 的代理与防火墙,也支持
wss://(基于 TLS)。
一句话总结:WebSocket 握手本质上是一次带 Upgrade 头的 HTTP 请求,服务端回 101 后双方从"一问一答"切换为"随时互喊"的全双工模式。
🔬 扩展知识
详情
- 【L3】
Sec-WebSocket-Key/Accept不是加密机制,而是协议能力探测:防止请求被普通 HTTP 服务器误当成普通请求处理,也防止缓存代理返回错误缓存。 - 【L3】WebSocket 长连接需要应用层心跳保活:中间设备(NAT、负载均衡、防火墙)会清理空闲连接,通常用 ping/pong 帧定期探活。
🔀 发散问题
- Q:为什么不直接定义新协议,而要借用 HTTP 握手? → 复用 80/443 端口与企业已有的代理、防火墙基础设施,无需额外开通端口即可完成升级。
- Q:WebSocket 和 HTTP 长轮询如何选择? → 长轮询实现简单但每次都要重新发请求、头部开销大;消息频繁的双向实时场景用 WebSocket,低频通知场景长轮询/SSE 也可接受。
【中等】HTTPS 的证书链验证过程是怎样的?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / HTTPS
💎 关键结论
浏览器信任的不是服务器证书本身,而是一条从服务器证书到受信任根证书的完整证书链。验证过程就是沿着"服务器证书 → 中间 CA → 根 CA"逐级向上验签"找背书",任何一环断裂(签名无效、过期、域名不符、被吊销),浏览器都会拒绝连接。
⚡记忆卡片
- 口诀:叶子到中间,验签到根;一环断裂,拒绝连接
- 关键词:叶子证书 / 中间 CA / 根证书 / 吊销检查 / 信任库
- 链路:服务器下发证书链 → 逐级验签 → 命中内置根证书 → 检查过期/域名/吊销 → 信任公钥
📖 核心知识
验证流程
- 服务器下发证书链:叶子证书(服务器证书)+ 若干中间 CA 证书。
- 客户端用签发者(Issuer)的公钥验证每张证书的数字签名,确认未被篡改且确由上级 CA 签发。
- 逐级向上查找,直到命中浏览器/操作系统内置信任库中的根 CA 证书(自签名,天然可信)。
- 沿途还要逐项检查:证书是否过期、域名是否匹配(含通配符和 SAN 列表)、是否被吊销(CRL 或 OCSP Stapling)。
- 全部通过后,才信任服务器公钥,继续 TLS 握手。
为什么要用证书链
- 根 CA 私钥极其敏感,通常离线保存;由中间 CA 代为签发,泄露风险可控、可局部吊销。
- 客户端只需预置少量根证书,即可验证全球任意网站的证书。
🔬 扩展知识
详情
- 【L3】吊销检查有 CRL(吊销列表)与 OCSP(在线查询)两种,实践中多用 OCSP Stapling 由服务端代查并随握手下发,避免客户端实时查询的延迟与隐私问题。
- 【L3】根 CA 私钥离线保存(HSM 冷存储),日常签发全部委托给中间 CA:中间 CA 泄露只需吊销该中间证书,不影响整个信任体系。
🔀 发散问题
- Q:为什么 PC 上证书正常、手机上却报错? → 移动端通常不会自动补链,服务端必须下发"叶子 + 中间证书"的完整链,桌面浏览器能凭 AIA 扩展自动下载缺失的中间证书。
- Q:自签名证书与 CA 签发证书的区别? → 自签名证书没有可回溯到受信根的信任链,浏览器默认不信任,只适合内部系统与测试环境。
TCP
【简单】什么是 TCP 协议?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / TCP 协议
💎 关键结论
TCP(Transmission Control Protocol),即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。它通过连接管理、确认重传、排序机制、流量控制四大机制,在不可靠的 IP 网络之上提供可靠交付。
⚡记忆卡片
- 口诀:握手建连、确认重传、序号排序、窗口控速
- 关键词:面向连接 / 可靠 / 字节流 / 流量控制
- 链路:三次握手建连 → 字节流传输 → 确认重传保可靠 → 四次挥手断连
📖 核心知识
核心机制
| 机制 | 作用 | 简单比喻 |
|---|---|---|
| 连接管理 | 通过三次握手建立连接,四次挥手断开连接。 | 打电话前先拨通,说完再见再挂断。 |
| 确认重传 | 接收方收到包必须回复确认,发送方没收到确认就重发。 | 寄挂号信,必须签收回执,没回执就再寄。 |
| 排序机制 | 给每个数据包标序号,接收方按序号重组,保证数据有序。 | 拼图游戏,每块都有编号,按顺序拼好。 |
| 流量控制 | 接收方告知自身处理能力,防止发送方发得太快导致数据溢出。 | 根据食堂阿姨打饭快慢,调整递盘子的速度。 |
🔬 扩展知识
详情
- 【L3】除上述四大机制外,TCP 还有拥塞控制(慢启动、拥塞避免等):流量控制看的是接收方处理能力,拥塞控制看的是网络链路承载能力,二者共同决定发送速率。
- 【L4】TCP 的可靠性是端到端实现的,底层 IP 只负责尽最大努力交付,丢包、乱序、重复都由 TCP 在两端自行修复——这也是"UDP 之上自建可靠层"(如 QUIC)可行的原因。
🔀 发散问题
- Q:TCP 和 UDP 怎么选? → 要准确选 TCP(网页、文件传输),要速度选 UDP(直播、语音),详见本文档「TCP 和 UDP 有什么区别?」。
- Q:TCP 为什么需要"连接"? → 连接的本质是双方各自维护序号、窗口、缓冲区等状态,没有这些状态就无法实现可靠、有序的字节流交付。
【中等】TCP 三次握手的过程是怎样的?⭐⭐⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / TCP 连接管理
💎 关键结论
三次握手负责建立 TCP 双向连接:SYN → SYN/ACK → ACK,共 1 RTT。它既确认了双方的收发能力正常,又防止历史连接和伪造 SYN 白白消耗服务端资源。
⚡记忆卡片
- 口诀:SYN 问、SYN+ACK 答、ACK 确认成连接
- 关键词:SYN / ACK / 半连接队列 / ESTABLISHED
- 链路:SYN → SYN+ACK → ACK → 双方 ESTABLISHED
📖 核心知识
什么是三次握手?
如上图所示,三次握手流程如下:
- 第一次握手 - 客户端向服务端发送带有 SYN 标志的数据包。
- 第二次握手 - 服务端向客户端发送带有 SYN/ACK 标志的数据包。
- 第三次握手 - 客户端向服务端发送带有带有 ACK 标志的数据包。
至此,TCP 三次握手完成,客户端与服务端已建立双向连接。
💡 说明:SYN 为 synchronize 的缩写,ACK 为 acknowledgment 的缩写。
为什么需要三次握手?
为了便于说明,假设客户端为 A, 服务端为 B。
- 第一次握手,A 向 B 发同步消息。B 收到消息后,B 认为:A 发消息没问题;B 收消息没问题。
- 第二次握手,B 向 A 发同步消息和确认消息。A 收到消息后,A 认为:A 发消息、收消息都没问题;B 发消息、收消息都没问题。但是,此时 B 不确定自己发消息是否没问题,所以就需要第三次握手。
- 第三次握手,A 向 B 发确认消息。B 收到消息后。B 认为:B 发消息没问题。
为什么不能是两次握手?
- 防止历史连接浪费资源:客户端因网络拥塞重发了一个早已超时的旧 SYN,若只有两次握手,服务端收到即建立连接并分配资源,客户端却不认账——白白消耗内存与连接表项。三次握手中客户端会在第三次确认时丢弃过期的连接。
- 防止 SYN Flood 零成本攻击面扩大:三次握手让服务端把资源分配推迟到收到第三次 ACK 之后;若两次就建连,伪造源 IP 的攻击者发一个 SYN 就能换走一份服务端资源。
- 确认 B 的发送能力:如上所述,两次握手时 B 无法确认自己的报文能到达 A。
各状态存在的意义
| 状态 | 存在于 | 意义 |
|---|---|---|
| LISTEN | 服务端 | 被动等待连接,占用一个监听 socket |
| SYN_SENT | 客户端 | SYN 已发出,等待确认;超时则指数退避重试 |
| SYN_RCVD | 服务端 | 半连接(未完成握手),占用半连接队列(backlog),是 SYN Flood 的攻击目标 |
| ESTABLISHED | 双方 | 全连接,进入数据传输阶段 |
🔬 扩展知识
详情
- 【L3】方案权衡:
| 方案 | 建连开销 | 适用边界 / 代价 |
|---|---|---|
| 标准三次握手 | 1 RTT | 通用默认,连接状态可靠 |
| TCP Fast Open(TFO) | 首包数据随 SYN 发出,约 0 RTT | 仅适合幂等请求;有重放风险,部分中间盒会丢弃带数据的 SYN |
| HTTP Keep-Alive / 连接池 | 后续请求 0 RTT | 真正省握手的是复用连接,而非改协议 |
- 【L4】SYN Flood 攻击面:攻击者伪造源 IP 发海量 SYN,服务端回 SYN+ACK 后永远等不到第三次 ACK,半连接队列(
tcp_max_syn_backlog)被打满,正常用户握手被丢弃。防御:tcp_syncookies = 1(把连接信息编码进序列号,不占半连接队列,但丢失部分 TCP 选项);加大 backlog;前置 LB/防火墙做 SYN Proxy。
🏭 实战场景
详情
- 踩坑案例:大促压测时客户端大量
connect timeout,服务端 CPU 却很低。排查:netstat -s显示 "times the listen queue of a socket overflowed",ss -lnt看到 Recv-Q 逼近 Send-Q(backlog)。根因:应用设置的 listen backlog 只有 128,高并发下 SYN+ACK 排队溢出被丢弃。修复:同步调大内核somaxconn、tcp_max_syn_backlog和应用 backlog 参数,压测通过。 - 场景题:新服务上线后,高峰期监控发现 TCP 重连率飙升,客户端日志满是"连接超时",服务端应用日志却无任何报错,如何定位?
- 应急处理:先扩容实例或前置限流降低单机握手速率;同时检查是否正遭 SYN Flood(源 IP 分布是否离散、半连接队列是否打满)。
- 根因分析:服务端无报错说明请求没到应用层——问题在握手阶段。
ss -lnt看 backlog 是否溢出、dmesg看 "overflowed" 日志、netstat -s看 SYN 丢弃计数;区分是 backlog 配置过小(正常流量也丢)还是攻击(syncookies 计数增长)。 - 长期方案:backlog 与应用并发能力联动配置;开启 syncookies 兜底;接入层部署 SYN Proxy 把握手压力挡在业务集群外;对客户端做指数退避重试避免重试风暴。
- 权衡:syncookies 常开虽安全但损失 TCP 选项(影响大带宽场景的窗口缩放);更优做法是仅靠足够大的 backlog + 快速扩容,把 syncookies 保留为兜底开关。
⚠️ 常见误区
详情
- ❌ "两次握手也能建立连接" → 两次握手无法确认服务端的发送能力,且历史重复 SYN 会让服务端白白建立连接浪费资源,还会放大 SYN Flood 攻击面。
- ❌ "三次握手时会传输应用数据" → 标准握手的三个报文不携带应用数据(TCP Fast Open 例外,且仅限幂等请求)。
- ❌ "连接超时一定是服务挂了" → backlog 溢出、SYN 被中间设备丢弃、半连接队列打满都会表现为握手超时,应用层日志往往毫无痕迹。
🔀 发散问题
- Q:为什么初始序列号(ISN)要随机生成? → 一是防止旧连接的迟到报文被新连接误收;二是防序列号预测攻击,若 ISN 可预测,攻击者可盲发伪造报文实施连接劫持或 RST 注入。
- Q:第三次握手的 ACK 丢了会发生什么? → 服务端处于 SYN_RCVD,若随后收到客户端数据包则连接正常建立;若一直收不到数据,服务端超时后发 RST 清理半连接。客户端已 ESTABLISHED,实际影响很小。
- Q:SYN Cookie 为什么能防 SYN Flood,代价是什么? → 把四元组等信息编码进 SYN+ACK 的序列号,收到第三次 ACK 验算通过才分配资源,半连接队列不再是瓶颈;代价是丢失窗口缩放、SACK 等 TCP 选项且验算耗 CPU,故只在队列溢出时启用。
【中等】TCP 四次挥手的过程是怎样的?⭐⭐⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / TCP 连接管理
💎 关键结论
四次挥手负责断开 TCP 双向连接:FIN → ACK → FIN → ACK。因为关闭方向是双向的且服务端可能还有数据未发完,ACK 和 FIN 通常分开发送,比握手多一次。主动关闭方最后进入 TIME_WAIT,等待 2MSL(Linux 上固定 60 s)。
⚡记忆卡片
- 口诀:FIN 请闭、ACK 知晓、FIN 同意、ACK 告别
- 关键词:FIN / CLOSE_WAIT / TIME_WAIT / 2MSL
- 链路:FIN → ACK → FIN → ACK → 主动方 TIME_WAIT(60 s)→ 彻底关闭
📖 核心知识
什么是四次挥手?
如上图所示,四次挥手流程如下:
- 第一次挥手 - 客户端向服务端发送一个 FIN 包,用来关闭客户端到服务端的数据传送。
- 第二次挥手 - 服务端收到这个 FIN 包,向客户端发送一个 ACK 包,确认序号为收到的序号加 1。和 SYN 一样,一个 FIN 将占用一个序号。
- 第三次挥手 - 服务端关闭与客户端的连接,向客户端发送一个 FIN 包。
- 第四次挥手 - 客户端向服务端发送 ACK 包,并将确认序号设置为收到序号加 1。
为什么建立连接是三次握手,关闭连接却是四次挥手呢?
- 建立连接的时候, 服务器在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把 ACK 和 SYN 放在一个报文里发送给客户端。
- 而关闭连接时,服务器收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送 FIN 报文给对方来表示同意现在关闭连接,因此,己方 ACK 和 FIN 一般都会分开发送,从而导致多了一次。
各状态存在的意义与 TIME_WAIT 的量化
| 状态 | 意义 |
|---|---|
| FIN_WAIT_1 / FIN_WAIT_2 | 主动方已发出 FIN,等待对方确认与对方的 FIN |
| CLOSE_WAIT | 被动方收到 FIN 但本地还有数据要发;大量堆积几乎必然是应用层忘记调用 close(),属于代码 bug |
| LAST_ACK | 被动方发出 FIN,等待最后一个 ACK |
| TIME_WAIT | 主动方发出最后一个 ACK 后等待 2MSL,Linux 上 MSL 写死为 30 s,即固定 60 s |
为什么 TIME_WAIT 要等 2MSL(60 s)
- 保证最后一个 ACK 可靠送达:若 ACK 丢失,被动方会重发 FIN,主动方在 2MSL 窗口内还能再回一次 ACK。
- 让本连接的迟到报文在网络中自然消亡,防止被同四元组的新连接误收。
大量产生 TIME_WAIT 的典型场景
- 短连接 + 高并发外呼:如网关/压测客户端频繁新建并主动关闭连接,60 s 窗口内每条连接都占一个临时端口。
- 量化:Linux 临时端口默认 32768~60999,约 2.8 万个;单机短连接速率超过约 460 conn/s 时理论值即开始逼近上限,耗尽后
connect报EADDRNOTAVAIL(Cannot assign requested address)。
🔬 扩展知识
详情
- 【L3】治理 TIME_WAIT 的方案权衡:
| 方案 | 说明 | 适用条件 / 代价 |
|---|---|---|
tcp_tw_reuse = 1 | 复用时间戳较新的 TIME_WAIT 端口 | 仅对主动发起的外出连接(客户端角色)生效,依赖 TCP 时间戳;对作为服务端的入向连接无效 |
扩大 ip_local_port_range | 增加可用端口池 | 治标不治本,只是抬高上限 |
| 连接池 + Keep-Alive | 减少新建连接数 | 治本之策 |
| 让对端主动关闭 | 把 TIME_WAIT 转移到对端 | 需双方协商关闭时序 |
- 【L4】
tcp_tw_recycle在 NAT 环境下会导致连接随机丢失,Linux 4.12 已彻底移除,禁止在生产配置中残留。 - 【L3】更多治理手段与注意事项,见本文档「TCP TIME_WAIT 过多是什么原因?如何解决?」。
🏭 实战场景
详情
- 踩坑案例:支付网关高峰期偶发调外部 HTTPS 接口失败,错误日志为
Cannot assign requested address,重启后短暂恢复。排查:ss -s显示 TIME_WAIT 高达 2.7 万条,与临时端口上限吻合;确认代码每次请求新建 HttpClient 且由本端主动关闭。根因:短连接外呼把 2.8 万个临时端口在 60 s 内全部打成 TIME_WAIT。修复:改用带连接池的 HttpClient(Keep-Alive 复用),同时开启tcp_tw_reuse兜底,故障消除。 - 场景题:某服务发版后,监控显示 ESTABLISHED 连接数缓慢下降,CLOSE_WAIT 从个位数涨到数千且不回落,业务方反馈长连接客户端开始报"对端无响应",如何处理?
- 应急处理:CLOSE_WAIT 只能靠进程退出或应用修复释放,先滚动重启受影响实例恢复服务,同时降低发版流量比例防止二次爆炸。
- 根因分析:CLOSE_WAIT 只可能由应用产生——对端已发 FIN,本端内核回了 ACK 但应用没调
close()。用lsof -p/ss -tnp定位泄漏 fd 归属的线程与代码路径;结合发版 diff 排查连接管理改动,典型原因是异常分支提前 return 跳过了 finally 中的关闭逻辑。 - 长期方案:引入连接池统一管理生命周期;对连接加空闲超时与主动探活;在监控中加入 CLOSE_WAIT 数量与 fd 使用率告警,纳入发布观察项。
- 权衡:激进的连接超时会误杀慢请求,探活间隔要与业务最长请求耗时对齐;比无限信任"代码会关连接",用机制兜底更可靠。
⚠️ 常见误区
详情
- ❌ "打开
tcp_tw_recycle能快速清理 TIME_WAIT" → 该参数在 NAT 环境下会导致连接随机丢失,Linux 4.12 已彻底移除,禁止在生产配置中残留。 - ❌ "大量 CLOSE_WAIT 是内核或网络问题" → 几乎必然是应用层忘记调用
close()(连接泄漏),fd 永不释放,最终耗尽进程文件描述符,属于代码 bug。 - ❌ "把 2MSL 调短就能治理 TIME_WAIT" → Linux 上 MSL 是内核编译常量(30 s),无法通过 sysctl 调整;即使能调,缩短会牺牲可靠性。正确思路是
tcp_tw_reuse+ 连接池。
🔀 发散问题
- Q:主动关闭和被动关闭谁更容易出问题? → 主动方产生 TIME_WAIT,高并发短连接下会耗尽临时端口导致建连失败;被动方若出现大量 CLOSE_WAIT,说明应用没有及时
close()(连接泄漏)。 - Q:最后一个 ACK 丢失会发生什么? → 主动方在 TIME_WAIT 内收不到重发的 FIN 就正常到期关闭;被动方等不到 ACK 会超时重发 FIN,若超过重试上限则发 RST 强制关闭。这正是 2MSL 等待存在的理由。
- Q:TIME_WAIT 太多怎么办? → 治本靠连接池 + Keep-Alive 减少新建连接,兜底用
tcp_tw_reuse(仅客户端角色生效),详见本文档「TCP TIME_WAIT 过多是什么原因?如何解决?」。
【中等】TCP 滑动窗口原理是什么?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / TCP 流量控制
💎 关键结论
滑动窗口是 TCP 的一种控制网络流量的技术。 TCP 必需要解决的可靠传输以及包乱序(reordering)的问题,必需要知道网络实际的数据处理带宽或是数据处理速度,这样才不会引起网络拥塞,导致丢包。TCP 头里有一个字段叫 Window,又叫 Advertised-Window,这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。
⚡记忆卡片
- 口诀:接收方报窗口,发送方按量发,确认即滑动
- 关键词:Window / Advertised-Window / 流量控制 / 缓冲区
- 链路:ACK 携带窗口值 → 发送方维护发送窗口 → 收到确认窗口向前滑动
📖 核心知识

滑动窗口把发送方的数据划分为四类区域:
- 已发送已确认 - 数据流中最早的字节已经发送并得到确认。这些数据是站在发送端的角度来看的。上图中的 31 个字节已经发送并确认。
- 已发送但尚未确认 - 已发送但尚未得到确认的字节。发送方在确认之前,不认为这些数据已经被处理。上图中的 32 ~ 45 字节为第 2 类。
- 未发送而接收方已 Ready - 设备尚未将数据发出 ,但接收方根据最近一次关于发送方一次要发送多少字节确认自己有足够空间。发送方会立即尝试发送。上图中的 46 ~ 51 字节为第 3 类。
- 未发送而接收方 Not Ready - 由于接收方 not ready,还不允许将这部分数据发出。上图中的 52 以后的字节为第 4 类。

这张图片相对于上一张图片,滑动窗口偏移了 5 个字节,意味着有 5 个已发送的字节得到了确认。
🔬 扩展知识
详情
- 【L3】零窗口(Zero Window):接收方缓冲区满时会通告窗口为 0,发送方暂停发送,并定期发送窗口探测报文避免双方死锁(窗口更新报文丢失时)。
- 【L3】流量控制与拥塞控制的分工:滑动窗口面向接收方处理能力,拥塞窗口面向网络链路承载能力,发送方实际发送量取两者较小值。
🔀 发散问题
- Q:滑动窗口和拥塞窗口有什么区别? → 滑动窗口由接收方通告,防接收方处理不过来;拥塞窗口由发送方根据网络丢包/延迟估算,防打满链路;实际发送窗口取两者较小值。
- Q:窗口通告丢了怎么办? → 发送方会沿用旧窗口值继续发送,若接收方窗口已缩小可能超发;TCP 通过窗口探测与持续确认机制恢复一致。
【中等】TCP 重传机制是什么?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / TCP 可靠传输
💎 关键结论
TCP 重传机制确保数据可靠传输,应对网络丢包:超时重传(RTO 定时器)是最后保险,快速重传(收到 3 个重复 ACK 立即重传)提升效率,SACK 进一步实现精确重传、只重传真正丢失的包。
⚡记忆卡片
- 口诀:超时兜底、三重复快重、SACK 精准补
- 关键词:RTO / 重复 ACK / 快速重传 / SACK
- 链路:丢包 → 后续包到达触发重复 ACK → 快速重传 → SACK 精确补洞 → 超时重传兜底
📖 核心知识
四大触发原因
- 数据包丢失(真丢了)
- 确认 ACK 丢失(对方回了,回执丢了)
- 确认 ACK 延迟(回执来太慢,等不及了)
- 接收方处理慢(对方收到了但没来得及回)
两大核心机制
| 机制 | 工作原理 | 特点 |
|---|---|---|
| 超时重传 | 为一个包启动定时器,时间到了(**RTO **超时)就重传。 | 最后保险,效率低,性能差。 |
| 快速重传 | 收到** 3 个重复 ACK**(意味着后序包到了但前面缺包),不等超时立刻重传缺包。 | 效率高,大幅减少等待时间。 |
优化补丁:SACK
- 作用:在快速重传基础上,接收方告诉发送方具体丢了哪些包。
- 好处:实现精确重传,只重传真正丢失的包,避免浪费带宽。
🔬 扩展知识
详情
- 【L3】RTO 不是固定值,而是基于 RTT(往返时间)采样动态估算:网络抖动时 RTO 自适应变长,避免无谓重传。
- 【L3】快速重传以"收到 3 个重复 ACK"为触发条件,本质是利用"后续包已到达"这一证据判断前面的包丢失,从而不等超时就提前补救。
🔀 发散问题
- Q:为什么快速重传要等 3 个重复 ACK,而不是 1 个? → 网络中报文可能乱序到达,过早重传会浪费带宽;3 个重复 ACK 意味着后续多个包都已到达,缺包基本可以确认,是及时性与抗乱序的折中。
- Q:SACK 如何避免盲目重传? → 接收方在 ACK 中明确告知已收到的字节区间,发送方只对空洞区间重传,避免把已送达的数据再发一遍。
【困难】TCP 的粘包和拆包能说说吗?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:15 min | 🏷 标签:计算机网络 / TCP 可靠传输
💎 关键结论
TCP 是字节流协议,只保证数据顺序,不维护应用层消息的边界。粘包拆包是字节流特性的必然现象,必须在应用层自行定义消息边界,而在消息头中携带长度字段是最通用、最有效的解决方案。
⚡记忆卡片
- 口诀:字节流无边界,长度字段定边界
- 关键词:字节流 / 粘包 / 半包 / 长度字段 / 帧解码器
- 链路:应用消息写入 → TCP 按段合并/拆分 → 接收方按长度头切分还原
📖 核心知识
像用消防水管喝水,发送方是一杯杯倒(消息),接收方是一桶桶接(字节流),一桶里可能有多杯或半杯。
| 现象 | 描述 | 简单比喻 |
|---|---|---|
| 粘包 | 接收方一次收到多个应用消息包。 | 收到[AB]而不是[A][B] |
| 拆包/半包 | 接收方一次只收到一个应用消息包的部分。 | 收到[A-]和[-B]而不是完整的[A] |
最主流解决方案:长度字段法
在应用层协议中,给每个消息添加一个固定长度的消息头,头里写明后面消息体的长度。
- 发送端:先发 4 字节头(长度),再发实际数据。
- 接收端:先读取
4字节头,解析出长度 N;再读取 N 字节,即为一个完整应用消息。
这是绝大多数 RPC 框架(如 gRPC、Dubbo)和自定义二进制协议的首选方案。
其他解决方案
| 方法 | 做法 | 优点 | 缺点 | 应用场景 |
|---|---|---|---|---|
| 定长法 | 每个消息固定长度 | 简单 | 浪费带宽 | 极少使用 |
| 分隔符法 | 用特殊字符(如\n)标记消息结束 | 灵活 | 需处理内容转义 | 文本协议(如 Redis) |
| 用现成协议 | 使用 HTTP 等高级协议 | 省心 | 开销可能较大 | Web 应用 |
🔬 扩展知识
详情
- 【L3】长度字段法的工程实现:Netty 提供
LengthFieldBasedFrameDecoder,按配置的长度字段偏移与字节数自动完成半包等待与粘包切分,是自定义二进制协议的标准做法。 - 【L3】分隔符法(如 Redis 的
\r\n)必须处理内容中的转义问题,否则消息体中的分隔符会提前截断消息,因此二进制协议首选长度字段法。
🏭 实战场景
详情
- 案例:自研协议的订单推送服务高峰期出现解析报错与消息错位,日志显示偶发"消息体超长/截断"。排查:发送端把多条小报文连续写入 socket,TCP 按字节流合并发送,接收端却按固定假设长度切分,遇到合并或拆分即错位。根因:协议头未携带消息长度,依赖了不存在的"消息边界"。修复:消息头增加 4 字节长度字段,接收端改用按长度字段解码的帧解码器,异常消失。
- 排查思路:先在抓包/日志中确认"错位的是应用消息还是 TCP 段";再检查协议是否有长度字段或分隔符;最后验证发送端是否批量写入、接收端缓冲区是否按完整消息消费。
⚠️ 常见误区
详情
- ❌ "粘包是 TCP 协议的 bug" → 字节流不维护消息边界是 TCP 的固有设计,边界必须由应用层协议自己定义。
- ❌ "发送方 send 几次,接收方就 recv 几次" → TCP 分段与合并由内核根据 MSS、窗口、缓冲状态决定,与应用写入次数无一一对应关系。
- ❌ "UDP 也会粘包" → UDP 每个 datagram 独立交付、有消息边界,不存在粘包(IP 层分片是另一回事)。
🔀 发散问题
- Q:为什么 HTTP 不需要担心粘包? → HTTP/1.1 用 Content-Length 或 chunked 编码定义消息边界,HTTP/2 用二进制帧,本质上都是应用层自己定义边界。
- Q:Nagle 算法和粘包有什么关系? → Nagle 会把小包合并后发送,加剧粘包现象并可能增加小包延迟,实时性要求高的场景常用 TCP_NODELAY 关闭它。
【中等】TCP 和 UDP 有什么区别?⭐⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / 传输协议对比
💎 关键结论
- TCP:可靠优先,像打电话,需要连接和确认。
- UDP:速度优先,像发短信/喊话,无连接直接发。
- 本质是权衡:用 TCP 的延迟换取可靠,或用 UDP 的不可靠换取低延迟。
⚡记忆卡片
- 口诀:TCP 打电话,UDP 喊话;要准确 TCP,要速度 UDP
- 关键词:面向连接 / 可靠 / 字节流 / 数据报文 / 拥塞控制
- 链路:TCP:三次握手 → 字节流可靠传输 → 四次挥手;UDP:即发即走
📖 核心知识
核心对比
| 特性 | TCP (传输控制协议) | UDP (用户数据报协议) |
|---|---|---|
| 连接 | 面向连接 (需三次握手) | 无连接 (直接发送) |
| 可靠性 | 可靠,不丢包,不乱序 | 不可靠,尽最大努力交付 |
| 传输模式 | 字节流 (需处理粘包) | 数据报文 (有消息边界) |
| 速度 | 慢 | 快 |
| 控制机制 | 有流量控制、拥塞控制 | 无任何控制 |
如何选择
- 要准确:选 TCP。用于网页、邮件、文件传输。
- 要速度:选 UDP。用于视频、语音、直播、游戏。
量化差异与选型边界
| 维度 | TCP | UDP |
|---|---|---|
| 头部开销 | 20~60 字节 | 仅 8 字节 |
| 建连开销 | 1 RTT 三次握手 | 0,即发即走 |
| 拥塞控制 | 有(CUBIC/BBR 等),拥塞时主动降速 | 无,发多快完全由应用决定,容易打满链路造成丢包风暴 |
| 消息边界 | 无(字节流,需自行处理粘包) | 有(每个 datagram 独立交付) |
| 场景 | 推荐 | 理由 |
|---|---|---|
| 网页、API、文件传输 | TCP | 一个字节都不能错,重传延迟可接受 |
| 直播、语音、云游戏 | UDP(RTP/WebRTC) | 重传一帧旧画面不如直接丢弃,延迟 > 完整性 |
| DNS 查询、服务发现 | UDP | 报文小、一问一答,快优先;响应超 512 字节才切 TCP |
| 弱网下的可靠传输 | QUIC(UDP + 自实现可靠层) | 兼得 UDP 的低延迟建连与 TCP 级的可靠性,且流间无队头阻塞 |
🔬 扩展知识
详情
- 【L3】QUIC 在 UDP 之上自实现可靠传输:序号、ACK、重传、拥塞控制全部重做,且每个流独立确认,从而消除 TCP 的队头阻塞,这也是 HTTP/3 的基础。
- 【L3】UDP 无拥塞控制,发送速率完全由应用决定:链路拥塞时会引发自身与他流一起丢包的丢包风暴,应用层必须自行限速。
🏭 实战场景
详情
- 踩坑案例:实时行情推送用 UDP 直发,客户端偶发数据跳变、缺帧。排查:客户端无重传逻辑,丢包直接丢弃;链路探测显示晚高峰丢包率 3%。根因:把"UDP 快"误当成"UDP 够用",缺了应用层可靠性设计。修复:应用层加序号 + 选择性重传 + 关键帧 FEC,非关键帧允许丢弃,体验与可靠性兼顾。
- 场景题:直播产品要求端到端延迟 < 1 s,可容忍少量丢帧,团队内有人提议"把现有 TCP 方案换成 UDP 就行",如何评估?
- 应急处理:若当前 TCP 方案卡顿投诉激增,先降级码率/分辨率降低带宽需求止血,而不是仓促换协议。
- 根因分析:TCP 在直播场景的问题不是带宽而是重传策略:丢一个包后续帧全部等待,延迟被放大。单纯换 UDP 只解决了"不等重传",却引入了丢包检测、帧排序、拥塞控制、NAT 穿透(ICE/STUN)等一整套新问题,工程量是原方案的数倍。
- 长期方案:选用成熟协议而非裸 UDP:WebRTC(自带拥塞控制 GCC + FEC)适合互动直播;SRT/RIST 适合推流链路;若必须自建,在 UDP 上实现选择性重传 + 关键帧保护。
- 权衡:自建可控性最强但维护成本高;成熟协议生态好但定制受限。延迟与可靠性永远是一对矛盾,可容忍丢帧的业务应该把预算花在 FEC 和抖动缓冲上,而不是无脑换传输协议。
⚠️ 常见误区
详情
- ❌ "UDP 快,直接用它传业务数据就行" → 高丢包链路(跨国、移动网络)直接用裸 UDP 会大面积丢失,必须在应用层补序号/重传或 FEC。
- ❌ "TCP 适合音视频实时传输" → 重传与队头阻塞带来卡顿,实时场景宁可丢帧也不能等重传。
- ❌ "UDP 无拥塞控制是纯优势" → 突发流量会冲击中间链路,导致自身与他流一起丢包,需应用层自行限速。
- ❌ "UDP 报文想发多大发多大" → 超过 MTU 的 UDP 报文被分片,任一分片丢失整包作废,大报文建议 QUIC 或自行分块。
🔀 发散问题
- Q:DNS 为什么默认用 UDP,什么时候会切到 TCP? → DNS 查询报文小、一问一答,UDP 无握手开销更快。当响应超过 512 字节(如 DNSSEC、大型 TXT 记录)或做区域传输(AXFR)时切换 TCP;现代 DNS over TLS/HTTPS 则全程走 TCP。
- Q:能不能在 UDP 之上自建可靠传输?代价是什么? → 可以,QUIC 就是这么做的:自实现序号、ACK、重传、拥塞控制与流量控制。代价是全部可靠性逻辑要在用户态重写,收益是绕过 TCP 的队头阻塞与内核协议栈的僵化限制。
- Q:内网微服务 RPC 为什么不直接用 UDP 追求极致低延迟? → 内网丢包率虽低但不为零,业务对数据完整性要求绝对;TCP 长连接 + 多路复用(HTTP/2)已能把握手开销摊薄到忽略不计,可靠性收益远大于微秒级延迟差异。
【中等】TCP TIME_WAIT 过多是什么原因?如何解决?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / TCP 连接管理
💎 关键结论
TIME_WAIT 是什么:四次挥手中,主动关闭方发送最后一个 ACK 后进入 TIME_WAIT 状态,持续 2*MSL(Linux 默认约 60 秒)才真正释放连接。治理思路是复用连接而不是消灭它。
⚡记忆卡片
- 口诀:主动关闭等六十秒,复用连接是解药
- 关键词:2MSL / 临时端口 / tcp_tw_reuse / 连接池
- 链路:主动关闭 → 最后一个 ACK → TIME_WAIT 60 s → 端口释放
📖 核心知识
为什么要等待 2*MSL
- 保证最后一个 ACK 可靠送达:若 ACK 丢失,对端会重发 FIN,本端可再次 ACK。
- 让网络中残留的旧报文自然消亡,防止其被新建的同四元组连接误收。
过多的典型原因
- 短连接 + 高并发:Web 服务器/压测客户端主动关闭大量连接。
- 作为客户端频繁外呼:每条连接都占用一个本地临时端口(默认约 28000 个),耗尽后出现
Cannot assign requested address。
解决方案
| 手段 | 说明 |
|---|---|
tcp_tw_reuse = 1 | 允许复用处于 TIME_WAIT 且时间戳更新的连接(客户端场景安全) |
| 扩大临时端口范围 | 调大 ip_local_port_range |
| 连接池 / HTTP Keep-Alive | 减少新建连接数量,治本之策 |
| 让对端主动关闭 | 如 Nginx 后端由上游关闭,把 TIME_WAIT 转移出去 |
一句话总结:TIME_WAIT 是 TCP 可靠性的必要代价,治理思路是复用连接而不是消灭它。
🔬 扩展知识
详情
- 【L3】
tcp_tw_reuse仅对主动发起的外出连接(客户端角色)生效,且依赖 TCP 时间戳;对作为服务端的入向连接无效,不是万能开关。 - 【L3】不建议打开
tcp_tw_recycle:NAT 场景下有严重问题(连接随机丢失),Linux 4.12 已移除该参数。 - 【L4】TIME_WAIT 与四次挥手的完整状态机分析,见本文档「TCP 四次挥手的过程是怎样的?」。
🔀 发散问题
- Q:TIME_WAIT 会影响服务端监听吗? → 不会直接影响:TIME_WAIT 占用的是主动关闭方的四元组(含临时端口),监听 socket 不受影响;受影响的是作为客户端频繁外呼时的临时端口池。
- Q:为什么不干脆取消 TIME_WAIT? → 它是保证最后一个 ACK 可靠送达与旧报文消亡的必要机制,取消会牺牲连接关闭的可靠性,正确做法是减少短连接而不是消灭状态。
DNS 与应用层
【简单】DNS 解析过程是怎样的?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / DNS
💎 关键结论
DNS(Domain Name System)将域名解析为 IP 地址。解析顺序:先查本地各级缓存,缓存未命中则交给本地 DNS 服务器,由它依次问根、顶级域、权威 DNS,最终拿到 IP。
⚡记忆卡片
- 口诀:先查缓存再问本地,根、顶级、权威一路问到底
- 关键词:浏览器缓存 / hosts / 本地 DNS / 根 DNS / 权威 DNS
- 链路:浏览器缓存 → 操作系统缓存 → 本地 DNS 服务器 → 根 DNS → 顶级域 DNS → 权威 DNS → 返回 IP
📖 核心知识
DNS 解析流程如下:
- 浏览器缓存:先查本地 DNS 缓存
- 操作系统缓存:查 hosts 文件和本地 DNS 缓存
- 本地 DNS 服务器:递归查询本地 DNS 服务器
- 根 DNS 服务器:返回顶级域(.com)的 DNS 服务器地址
- 顶级域 DNS:返回权威 DNS 服务器地址
- 权威 DNS:返回最终 IP 地址
🔬 扩展知识
详情
- 【L3】各级 DNS 都会缓存解析结果,缓存有效期由记录的 TTL 控制:这就是改 DNS 记录后全球生效需要一段时间的原因,也是 CDN 调度能就近生效的基础。
- 【L3】DNS 解析链路存在被劫持/污染的风险(解析到错误 IP);DNS over TLS / DNS over HTTPS 通过加密解析流量缓解此类问题,代价是全程走 TCP、开销略增。
🔀 发散问题
- Q:递归查询和迭代查询有什么区别? → 递归"包办到底",迭代"指路自己走",详见本文档「DNS 递归查询和迭代查询有什么区别?」。
- Q:为什么 DNS 不直接返回一个固定 IP? → 同一域名可能对应负载均衡集群、就近 CDN 节点或容灾切换,动态解析才能实现调度。
【简单】DNS 递归查询和迭代查询有什么区别?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / DNS
💎 关键结论
一次完整的 DNS 解析是**"客户端递归 + 服务器迭代"**的组合:客户端只问一次本地 DNS 服务器,由本地 DNS 服务器代为跑腿。递归是"包办到底",迭代是"指路自己走"。
⚡记忆卡片
- 口诀:递归包办到底,迭代指路自己走
- 关键词:递归查询 / 迭代查询 / 本地 DNS / 根 DNS
- 链路:客户端 →(递归)本地 DNS →(迭代)根 DNS → 顶级域 DNS → 权威 DNS
📖 核心知识
递归查询
- 被查询方必须给出最终答案(IP 或明确的失败),不许"踢皮球"。
- 典型场景:主机 → 本地 DNS 服务器,以及本地 DNS 查询其配置的转发器时。
迭代查询
- 被查询方若不知道答案,就返回"你该去问谁"(下一跳 DNS 服务器地址),由查询者自己继续问。
- 典型场景:本地 DNS 服务器 → 根 DNS → 顶级域 DNS → 权威 DNS。
为什么要这样设计
- 根服务器和顶级域服务器每天承受海量查询,只做迭代可以把递归的解析压力转嫁给各级本地 DNS,同时利用各级缓存大幅提速。
- 客户端逻辑保持简单,只需发一次请求、等一个答案。
一句话总结:递归是"包办到底",迭代是"指路自己走"——客户端享受递归的省心,DNS 服务器体系靠迭代分摊压力。
🔬 扩展知识
详情
- 【L3】递归的压力集中在本地 DNS:它要代客户端跑完整个查询链,也因此成为缓存命中率与解析性能的关键环节;运营商本地 DNS 的缓存策略直接影响用户解析结果。
- 【L3】迭代每一跳返回的是"下一跳地址"而非最终答案,因此各级服务器之间无状态、可水平扩展,这是根/顶级域服务器能用少量集群支撑全球查询的前提。
🔀 发散问题
- Q:递归查询会不会把根服务器压垮? → 不会。根服务器只做迭代不接递归,压力被分摊到全球各级本地 DNS,再加上各级缓存,真正打到根的查询比例很小。
- Q:本地 DNS 的缓存过期了会怎样? → 重新跑一遍迭代查询链;若查询失败,还可依靠负缓存避免短时间内反复查不存在的域名。
【简单】什么是 CDN?⭐
🎯 目标等级:L2 | ⏱ 建议用时:5 min | 🏷 标签:计算机网络 / CDN
💎 关键结论
CDN(Content Delivery Network,内容分发网络):将内容缓存到离用户最近的边缘节点,加速内容传输。核心原理是通过 DNS 智能解析,将用户请求导向最近的缓存节点,而非源服务器。
⚡记忆卡片
- 口诀:内容缓存就近拿,智能解析到最近
- 关键词:边缘节点 / 缓存 / DNS 智能解析 / 静态加速
- 链路:源站内容 → 分发到边缘节点 → DNS 智能解析调度 → 用户就近访问
📖 核心知识
- 定义:CDN 将内容缓存到离用户最近的边缘节点,加速内容传输。
- 核心原理:通过 DNS 智能解析,将用户请求导向最近的缓存节点,而非源服务器。
- 适用场景:静态资源加速(JS/CSS/图片)、视频流媒体、大文件下载。
🔀 发散问题
- Q:CDN 适合加速动态接口吗? → 动态内容不可缓存,加速收益有限;通常只对静态资源用 CDN,动态请求走源站或动态加速链路。
- Q:CDN 的缓存行为和什么有关? → 取决于响应的缓存头(Cache-Control 等),详见本文档「HTTP 缓存机制是如何工作的?」。
【中等】浏览器的跨域问题是如何产生的?CORS 预检请求是怎么回事?⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / 浏览器安全
💎 关键结论
跨域是浏览器同源策略的限制而非协议缺陷:浏览器限制脚本(JS)访问不同源(协议 + 域名 + 端口任一不同)的资源。CORS 用响应头"开绿灯",复杂请求先 OPTIONS 预检再放行,服务端配置才是关键。
⚡记忆卡片
- 口诀:同源策略限制,CORS 开绿灯,复杂请求先预检
- 关键词:同源策略 / CORS / 预检请求 / OPTIONS
- 链路:跨域请求 → 浏览器同源策略拦截 → 服务端 CORS 响应头 → (非简单请求)OPTIONS 预检 → 真实请求放行
📖 核心知识
同源策略:浏览器出于安全,限制脚本(JS)访问不同源(协议 + 域名 + 端口任一不同)的资源。这是跨域问题的根源。
CORS(跨域资源共享) 是 W3C 标准的解决方案,由服务端通过响应头声明允许哪些来源跨域:
Access-Control-Allow-Origin:允许的来源。Access-Control-Allow-Methods/Allow-Headers:允许的方法和自定义头。Access-Control-Allow-Credentials:是否允许携带 Cookie。
简单请求 vs 预检请求
- 简单请求:GET/HEAD/POST 且 Content-Type 限于
text/plain、multipart/form-data、application/x-www-form-urlencoded,无自定义头。浏览器直接发送,仅在响应头中校验权限。 - 非简单请求(如
Content-Type: application/json的 POST、PUT/DELETE、带自定义头):浏览器先自动发送一个 OPTIONS 预检请求,询问服务器是否允许;服务器返回允许的方法/头后,才发送真实请求。服务端可通过Access-Control-Max-Age缓存预检结果,减少 OPTIONS 次数。
一句话总结:跨域是浏览器同源策略的限制而非协议缺陷;CORS 用响应头"开绿灯",复杂请求先 OPTIONS 预检再放行,服务端配置才是关键。
🔬 扩展知识
详情
- 【L3】
Access-Control-Max-Age可让浏览器缓存预检结果,避免每次非简单请求都多一次 OPTIONS 往返,是高频接口的实用优化。 - 【L3】携带 Cookie 的跨域请求要求:
Access-Control-Allow-Credentials: true且Access-Control-Allow-Origin不能为通配符*,必须是具体来源。
🔀 发散问题
- Q:服务端之间的调用有跨域问题吗? → 没有。同源策略只是浏览器的安全机制,服务端 HTTP 调用不受此限制。
- Q:除了 CORS 还有什么跨域方案? → 反向代理把前后端变成同源(Nginx 转发)是最常用的工程方案;JSONP 只支持 GET 且有安全风险,已基本退出历史舞台。
【中等】HTTP 缓存机制是如何工作的?⭐⭐⭐⭐
🎯 目标等级:L2 | ⏱ 建议用时:10 min | 🏷 标签:计算机网络 / HTTP 缓存
💎 关键结论
HTTP 缓存分为强缓存(Cache-Control/Expires)和协商缓存(ETag/Last-Modified)两种策略:先查强缓存,命中则零请求直接用;未命中再走协商缓存,服务端比对后返 304 或 200。
⚡记忆卡片
- 口诀:强缓存零请求,协商走 304
- 关键词:Cache-Control / ETag / 304 / max-age / no-cache
- 链路:请求资源 → 强缓存命中? → 未命中发条件请求 → 服务端比对 → 304/200
📖 核心知识
核心分为强缓存(Cache-Control/Expires)和协商缓存(ETag/Last-Modified)两种策略。
完整决策流程
- 浏览器先查本地缓存是否命中强缓存:命中则直接用本地副本,状态码显示
200 (from disk/memory cache),不发任何网络请求。 - 未命中则发起协商缓存验证:携带
If-None-Match(对应 ETag)或If-Modified-Since(对应 Last-Modified)。 - 服务端比对后,未变化返回
304 Not Modified(无响应体,省带宽);已变化返回200与新内容。
头部的优先级与语义
| 头部 | 优先级 | 语义 |
|---|---|---|
Cache-Control | 高于 Expires | max-age 相对时间,不受客户端时钟影响;no-cache 可存但每次必须协商;no-store 完全不缓存;private 仅浏览器可缓存,CDN 不可 |
Expires | HTTP/1.0 兼容 | 绝对时间戳,客户端时钟不准即失效,仅作兜底 |
ETag | 高于 Last-Modified | 内容指纹,精度最高;多机器生成不一致时协商缓存失效 |
Last-Modified | 秒级精度 | 1 s 内多次修改无法感知,但生成成本低 |
🔬 扩展知识
详情
- 【L3】
no-store覆盖一切:响应含no-store时任何缓存策略都失效,敏感接口(如支付页)应显式声明。 - 【L3】多源站 ETag 不一致:多台服务器基于 inode/mtime 生成 ETag,经负载均衡命中不同机器时 ETag 变化,304 变 200,回源流量暴增;统一改为基于内容 hash 的弱 ETag 可解。
- 【L4】URL 即缓存键:缓存以 URL 为键,发布后资源路径变更即全量失效;反之,同名内容变更而 URL 不变会导致用户看到旧内容,这是"内容指纹文件名"策略的由来。
- 【L3】动态接口误缓存:未设置缓存头的接口被 CDN 默认缓存,会导致用户看到别人的数据(隐私事故),动态接口应显式声明不缓存或
private。
🏭 实战场景
详情
- 踩坑案例:CDN 回源流量突增 10 倍,源站 CPU 告警。排查:CDN 日志显示大量本应 304 的请求变成 200 全量回源。根因:源站扩容后新增机器的 ETag 生成规则不一致(基于 inode 而非内容 hash),同一资源在不同机器上 ETag 不同,协商缓存全部失效。修复:统一改为基于内容 hash 的弱 ETag,并对静态资源改用"文件名指纹 +
max-age=31536000, immutable"的长缓存策略,回源流量降回基线。 - 场景题:版本发布后客服接到大量投诉:用户看到的仍是旧版页面,强制刷新才恢复,而你们需要"发布后 5 分钟内全量生效",如何设计缓存策略?
- 应急处理:若已有线上问题,先让 CDN 对相关 HTML 执行缓存刷新(purge),牺牲一次回源流量换紧急生效。
- 根因分析:旧版残留是因为 HTML 入口被配了长缓存(或 CDN 默认缓存),用户浏览器在
max-age内不会向服务器确认。缓存设计把"静态资源"和"入口文件"混为一谈。 - 长期方案:分层缓存策略——JS/CSS/图片用内容指纹命名 + 一年强缓存;
index.html配no-cache每次协商;发布流程中先上新资源(新旧共存),再更新 HTML 引用,天然实现灰度与秒级生效,无需 purge。 - 权衡:完全禁用缓存虽生效即时但首屏性能崩盘;指纹 + 分层策略是当前最优解,代价是构建流程复杂度略增。对确需紧急下线的内容(如违规页面),仍需保留 CDN purge 能力作为兜底。
⚠️ 常见误区
详情
- ❌ "
no-cache就是不缓存" →no-cache允许缓存副本,但每次使用前必须向服务端协商验证(可能得到 304);真正禁止任何环节存储的是no-store。面试中答反这两个是高频翻车点。 - ❌ "缓存时间配得越长越好" → HTML 入口文件配长缓存会导致发布后用户看不到新版本;入口应配
no-cache,长缓存只给带内容指纹的静态资源。 - ❌ "CDN 上缓存什么响应都行" → 含 Set-Cookie 的用户相关响应若被共享缓存存下,会造成会话串号/隐私泄漏,应默认不缓存或标
private。
🔀 发散问题
- Q:
no-cache和no-store到底有什么区别? →no-cache允许缓存但每次必须协商验证,适合频繁变更但希望省带宽的内容;no-store禁止任何环节存储响应,适合含敏感信息的接口。 - Q:静态资源应该配什么缓存头才能兼得性能与更新时效? → 带内容指纹(hash)的资源配
Cache-Control: max-age=31536000, immutable永久强缓存;HTML 入口配no-cache每次协商。两者配合才是完整方案。 - Q:为什么 CDN 上要谨慎缓存含 Set-Cookie 的响应? → Cookie 通常与用户会话相关,若被共享缓存存下会造成会话串号/隐私泄漏,规范做法是默认不缓存或确保
Cache-Control: private。
参考资料
- 《计算机网络:自顶向下方法》
- 《TCP/IP 详解 卷 1:协议》