计算机网络核心知识点整合|一篇吃透 OSI、TCP/IP、TCP/UDP、DNS、ICMP、CDN
搞网络这么多年,我最大的体会是:很多人不是学不会,而是知识点太散,背完 OSI 七层忘了 TCP 三次握手,刚搞懂 DNS 又碰上一堆解析故障,最后全混成一锅粥。这篇文章我把最核心的几个知识模块——OSI、TCP/IP、TCP/UDP、DNS、ICMP、CDN——全部串起来,每一块都讲清楚“它解决什么问题、底层怎么运转、实际排障怎么用”,适合正在备考的在校生、准备跳槽的运维和开发,也适合刚接手网络维护、天天跟域名解析和网页卡顿打交道的朋友。
我不打算按教材顺序平铺直叙,而是按“先看分层模型建立全局观 → 再深入传输层协议 → 然后通过 DNS 和 ICMP 练习排查 → 最后落到 CDN 加速”这条线来走。这样读下来你会发现,网络技能不是背结论,而是你脑子里能浮现出一条完整的数据包旅行路线:从浏览器输入网址,到 DNS 查出 IP,再到 TCP 建连、数据分片传输,最后 CDN 帮你把内容就近送达。这条线打通了,面试、排障、性能优化都不会虚。
1. 分层模型:先搭好骨架,再谈其他
1.1 OSI 七层每层到底管什么
OSI 参考模型把网络通信拆成七层,每一层只干自己的活,层与层之间通过标准接口通信。我把每一层的作用和身边最常见的代表写出来,你对照着记会轻松很多:
| 层级 | 名称 | 核心职责 | 常见协议/设备 |
|---|---|---|---|
| 7 | 应用层 | 为应用提供网络服务接口,解析用户数据 | HTTP、HTTPS、DNS、FTP、SMTP |
| 6 | 表示层 | 数据格式转换、加密、压缩 | SSL/TLS(早期归属)、JPEG、ASCII |
| 5 | 会话层 | 建立、管理、终止会话 | NetBIOS、RPC |
| 4 | 传输层 | 端到端通信、分段、流量控制、可靠性 | TCP、UDP |
| 3 | 网络层 | 逻辑寻址、路由选择、分组转发 | IP、ICMP、路由器 |
| 2 | 数据链路层 | 物理寻址(MAC)、成帧、差错检测 | Ethernet、交换机、ARP |
| 1 | 物理层 | 比特流传输、电气信号、介质接口 | 网线、光纤、集线器 |
这里最容易混淆的是第 3、4 层。很多同学问:“IP 负责路由,TCP 负责可靠,那到底是谁先干活?”实际上数据发送从上往下走,接收从下往上走。你把“数据”想象成寄快递:应用层是填写快递单的内容,传输层是给包裹贴上“从哪里来、到哪里去、要不要签收”的标签,网络层是快递分拣中心规划走哪条路,链路层是每个驿站核对收货人门牌号,物理层则是货车走的高速公路。
七层模型的价值不在“考试要背”,而在于它给了你一个定位问题的坐标系。网站打不开,如果你能判断是第 7 层(应用配置)还是第 4 层(端口不通),排查范围立刻缩小八成。
1.2 为什么实际网络用 TCP/IP 而不是 OSI
OSI 是国际标准化组织设计的理论模型,完整但不接地气。实际互联网跑的是 TCP/IP 协议栈,它把层级合并成了四层:应用层(对应 OSI 5~7 层)、传输层、网络层、网络接口层(对应 OSI 1~2 层)。很多教材里也写“五层模型”,只是把网络接口层拆成了物理层和数据链路层,方便教学。
为什么 TCP/IP 能赢?关键在它“先有协议,后有模型”。TCP/IP 是先做出了能跑的 TCP、IP 协议,再总结出分层逻辑;OSI 则是先定标准,再找厂商实现,结果很多层(比如表示层、会话层)在实际工程里被应用层协议自己消化了。拿 HTTPS 举例,它在 TCP 之上做了 TLS 加密,但你很难说清加密到底属于表示层还是会话层,实践里大家都直接把它归到“应用层组合”。
所以我的建议是:学习用五层模型(更接近真实),面试和梳理概念用 OSI 七层(更完整),但心里始终明白——两者只是不同视角的划分方式,不是物理上真有七层设备在排队干活。
1.3 分层设计的关键动作:封装与解封装
分层最大的好处是“各管一段”,而支撑它的核心机制是封装。发送数据时,每一层都会给上层传来的数据加上自己的头部(有的还加尾部),这个过程叫封装;接收数据时,每一层再剥掉对应的头部,叫解封装。
举个例子,你在浏览器里输入一个网址并回车,大概会发生这样一串封装动作:
- 应用层生成 HTTP 请求报文,包含方法、路径、头部、正文。
- 传输层把 HTTP 报文当作“数据”,加上 TCP 头,里面最关键的是源端口和目的端口。
- 网络层给 TCP 报文再加上 IP 头,填入源 IP 和目标 IP。
- 链路层把 IP 包再包裹成数据帧,加上 MAC 地址和帧校验序列。
- 物理层把帧变成比特流发送出去。
接收方按相反顺序,每层只识别自己该看的头部,处理完后把内部数据交给上一层。这个机制解释了为什么抓包工具(Wireshark)里你能一层一层展开看:最外层是帧,中间是 IP,再往里是 TCP,最里边是应用数据。理解了封装,再看“MTU 分片”“TCP 分段”这类概念就顺理成章了——因为每一层对数据大小都有自己的限制,超了就得分块。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. TCP 与 UDP:传输层的两种哲学
2.1 TCP 的可靠性是用什么换来的
TCP 是面向连接的、可靠的、基于字节流的传输协议。它最核心的价值是三个:确认应答、超时重传、按序重组。面试和排障时绕不开的“三次握手、四次挥手”就是为这些能力服务的。
三次握手的本质,是通信双方确认“我能发、你能收”和“你能发、我能收”。很多人记不住状态变化,我习惯这么讲:
- 客户端先发 SYN(我打算连接你,我的初始序号是 x)。
- 服务端回 SYN + ACK(我收到了你的 SYN,我的初始序号是 y,确认你的 x)。
- 客户端再回 ACK(我收到了你的 SYN+ACK,开始传数据吧)。
为什么不是两次?因为如果只有两次握手,服务端无法确定客户端是否收到了自己的同步能力,可能造成连接假建立。为什么不是四次?因为同步与确认可以合并在一个包里,四次没有意义。
四次挥手就更有意思了,因为 TCP 是双向的,每一方向关闭都要单独确认一次:
- 主动关闭方发 FIN(我不再发数据了)。
- 被动方回 ACK(我知道了,但我还有数据没发完)。
- 被动方发完剩余数据后,发 FIN(我也不再发数据了)。
- 主动方回 ACK,然后等待一段时间(2MSL)才彻底关闭。
被动方在收到 FIN 后不能立即发 FIN,必须先把缓冲区里剩余的数据发完,所以就有了中间的 TIME_WAIT 状态和大量连接处于 CLOSE_WAIT 的问题。网上排障贴子里经常出现“服务器 CLOSE_WAIT 堆积”,根因多半是应用代码没正确调用关闭函数,而不是内核参数问题。
可靠性机制还有滑动窗口和拥塞控制。滑动窗口解决的是“发送方别把接收方塞爆”,它允许发送方在不等待逐包确认的情况下连续发多个报文,窗口大小由接收方通告。拥塞控制解决的是“发送方别把网络塞爆”,四种算法(慢启动、拥塞避免、快重传、快恢复)协同防止网络崩溃。这些机制加在一起,就构成了 TCP 的“可靠但昂贵”:头部开销大、连接有状态、存在队头阻塞。
2.2 UDP 的快与险:什么场景离不开它
UDP 是面向无连接的不可靠传输协议,没有握手、没有确认、没有重传和排序。它只做一件事:把应用层数据包封装成报文,直接丢给 IP 层。所以它快,但丢包、乱序、重复全不管,交给应用层自己兜底。
为什么还有大量场景非用 UDP 不可?三个原因:低延迟、少开销、支持广播组播。典型例子:
- DNS 查询:一次请求一个响应,用 TCP 先握手反而拖慢,所以绝大多数 DNS 查询走 UDP 53 端口。
- 音视频通话、直播:允许少量丢包换取实时性,卡顿 100 毫秒比丢一帧更致命。
- 在线游戏:玩家操作指令追求毫秒级送达,游戏协议层自己做插值补偿。
- DHCP:客户端还没有 IP,需要用广播发现服务器,只能走 UDP。
另外还有基于 UDP 的 QUIC 协议。它把可靠性搬到了应用层,并解决了 TCP 的队头阻塞问题,在 HTTP/3 里被广泛使用。所以不能简单说“UDP 不可靠所以不好”,而是看谁来做可靠性、在哪个层做。
2.3 TCP 与 UDP 的选型判断标准
给一张我从实际项目中总结的对比表,后面选型直接照着判断:
| 对比项 | TCP | UDP |
|---|---|---|
| 连接状态 | 面向连接,需三次握手 | 无连接,直接发 |
| 可靠性 | 确认、重传、排序 | 不保证 |
| 头部大小 | 20~60 字节 | 8 字节 |
| 传输方式 | 字节流 | 数据报文 |
| 流量控制 | 滑动窗口 | 无 |
| 拥塞控制 | 有 | 无 |
| 典型应用 | HTTP、FTP、SMTP、数据库连接 | DNS、DHCP、音视频、游戏、QUIC |
判断标准我用一句话归纳:先问业务能不能容忍重传延迟。容忍不了(实时交互类)→ 选 UDP 自己做补偿;容忍得了或者必须保证数据完整(文件、网页、支付)→ 选 TCP。还有一类,请求响应极短且原本就走 UDP(比如 DNS),就别强行改 TCP,除非需要传超大响应或保证数据完整性。
3. DNS:互联网的电话簿,从解析原理到故障实战
3.1 一次完整解析:递归查询与迭代查询
DNS(域名系统)的核心功能是把域名映射成 IP 地址。浏览器里输入 www.example.com 后,你的设备不会直接问根服务器要结果,而是走一条复杂的解析链。我把过程简化成四步:
- 客户端先查本地缓存(浏览器缓存、操作系统缓存、hosts 文件),命中就直接返回。
- 未命中则把请求发给配置的本地 DNS 服务器(比如你路由器里的 114.114.114.114),这叫递归查询——本地 DNS 负责帮你把最终答案找回来。
- 本地 DNS 收到请求后,依次向根 DNS、顶级域(com)DNS、权威 DNS 发起迭代查询:根服务器告诉你“com 的服务器在哪”,com 服务器告诉你“example.com 的权威服务器在哪”。
- 权威 DNS 给出最终 A 记录/AAAA 记录,本地 DNS 缓存结果并返回给客户端。
这里最容易混淆的两个词是“递归”和“迭代”。你要记住:客户端和本地 DNS 之间是递归(我不管你怎么查,必须给我最终结果);本地 DNS 和全球各级 DNS 服务器之间是迭代(我不断问“下一步去问谁”,逐步逼近答案)。
TTL(生存时间)是 DNS 里的重要参数。它决定记录在缓存里存活多久。调低 TTL 可以加快域名迁移后的生效速度,代价是增加解析请求量;调高 TTL 能减轻 DNS 压力,但迁移 IP 时全网生效会很慢。业务变更 IP 的老手都知道:提前 24~48 小时把 TTL 调低,变更后再调回来。
3.2 DNS 记录类型速查
日常维护和排障里,最常见的记录类型是下面这几条:
- A:域名 → IPv4 地址
- AAAA:域名 → IPv6 地址
- CNAME:域名 → 另一个域名(别名)
- MX:邮件服务器记录
- TXT:任意文本,常用于校验(SPF、DKIM、域名验证)
- NS:指定该域名的权威 DNS 服务器
- PTR:IP 反查域名(反垃圾邮件常用)
实际工作中 CNAME 用得非常频繁,尤其配合 CDN。你配置 CDN 时,通常把业务域名 CNAME 到 CDN 分配的加速域名,CDN 再通过自己的智能调度,把你引导到最近的边缘节点。这也是为什么很多新手检查 CDN 是否生效,第一步就是看域名解析结果是不是指向了 CDN 厂商的域名。
用命令行查记录是最基础的技能。Windows 上用 nslookup,Linux/macOS 上也可以用 dig,针对不同记录类型加参数即可:
bash复制# 查 A 记录
dig www.example.com A
# 查 CNAME
dig www.example.com CNAME
# 指定 DNS 服务器查询
dig @8.8.8.8 www.example.com
# 查 MX 记录
dig example.com MX
3.3 Linux 配置 DNS 全流程与坑
热词里有 “Ubuntu 22.04 修改 DNS” 和 “Linux 修改 DNS 后重启网络还原”,这两个问题我见得非常多。根源在于新版系统用 systemd-resolved 接管了 DNS,你直接改 /etc/resolv.conf,重启后就会被覆盖。
Ubuntu 22.04 的正确姿势有两种。第一种是临时修改,直接改 /etc/resolv.conf,但生效到重启为止。第二种是永久修改,推荐用 netplan(如果你用的 22.04 默认 netplan):
bash复制# 编辑网络配置文件
sudo vim /etc/netplan/01-network-manager-all.yaml
# 内容示例
network:
version: 2
ethernets:
eth0:
dhcp4: true
nameservers:
addresses: [223.5.5.5, 119.29.29.29]
search: [example.com]
# 应用配置
sudo netplan apply
如果你用的是固定 IP,记得把 dhcp4: true 改为 dhcp4: no,然后在 addresses 里填 IP、网关,再加 nameservers。改了之后别急着走人,用 resolvectl status 或 dig 验证一下。
另外还有一个隐蔽的坑:容器里改 /etc/resolv.conf 经常失败,因为 Docker 默认会为容器注入宿主机 DNS 配置。你需要在启动容器时通过 --dns 参数指定 DNS,或者在 /etc/docker/daemon.json 里配置 "dns": ["223.5.5.5"],再 systemctl restart docker。
3.4 自己搭建 DNS 服务器的思路
自己做 DNS 服务器,多半是为了内网解析、缓存加速、或者实验学习。最常见的一套是 Linux + dnsmasq,轻量、配置简单,几百行配置就能撑起小规模内网的域名解析。若需要完整的权威解析、视图分域(内网和外网返回不同 IP)、日志统计,就用 bind9。
我以 dnsmasq 为例,三步完成一个内网 DNS+缓存服务器:
- 安装:
sudo apt install dnsmasq - 编辑配置
/etc/dnsmasq.conf,加入:
bash复制# 监听内网地址
listen-address=192.168.1.2
# 本地域名解析
address=/gitlab.local/192.168.1.10
# 上游 DNS
server=223.5.5.5
server=119.29.29.29
# 缓存大小
cache-size=10000
- 重启服务:
sudo systemctl restart dnsmasq,再把内网其他机器或路由器的 DNS 指到192.168.1.2。
搭建过程中最需要关注的是防火墙放行 UDP/TCP 53 端口,以及主备方案。生产环境如果只有一台 DNS,挂了就是全网解析事故,至少做两台,或者用 Keepalived 做 VIP 漂移。
3.5 Chrome “无法找到 DNS”的排查路径
热词里有“Chrome 浏览器无法找到 DNS”,这是典型客户端侧报错,报错信息通常写成“找不到服务器 IP 地址”或“ERR_NAME_NOT_RESOLVED”。我的排查顺序是:
- 先用
ping测试公认 IP,判断网络通不通。 - 再用
nslookup直接查目标域名,看是全部域名解析失败,还是单个域名失败。 - 检查 hosts 文件是否写入了过期记录(Windows 路径
C:\Windows\System32\drivers\etc\hosts)。 - 检查系统 DNS 设置,换成公共 DNS(223.5.5.5、119.29.29.29)再试。
- 用
ipconfig /flushdns(Windows)或systemd-resolve --flush-caches(Linux)清理缓存。 - 最后才查路由器、运营商链路。
经验告诉我:如果所有域名都解析失败,八成是机器 DNS 配置指向了一个不可达的服务器;如果只有一个域名失败,先查是不是这个域名刚改了 NS 服务器,全球生效需要时间,或者被权威侧错误配置了。Chrome 自身也有一个 DNS 缓存,chrome://net-internals/#dns 可以手动清缓存,这是个常被忽略的细节。
4. ICMP 与网络诊断:Ping 和 Traceroute 的底层逻辑
4.1 ICMP 协议基础
ICMP(互联网控制报文协议)是网络层的辅助协议,它的工作不是传用户数据,而是传递错误报告和网络诊断信息。注意,ICMP 虽然用 IP 封装,但它不是传输层协议,不经过 TCP/UDP 端口。
最常见的 ICMP 消息类型有两种方向:
- 差错报告:目标不可达、超时、参数错误、源抑制(已基本弃用)。
- 查询消息:回显请求(Type 8)和回显应答(Type 0),这正是 Ping 程序的基础。
还有个很容易和“超时”混淆的点:数据包每经过一个路由器,TTL 减 1,减到 0 时路由器会丢弃该包并回送 ICMP 超时消息。Traceroute(Linux 下也叫 traceroute,Windows 下是 tracert)就是利用这个机制,通过发送初始 TTL 为 1、2、3……的包,让每个路由器都“暴露”自己的地址,从而画出路径。
4.2 Ping 和 Traceroute 实战排障
我在排查“网页加载慢、时断时通”这类问题时,几乎必用这两条命令。先 ping 目标 IP,观察三个指标:丢包率、往返时延、时延抖动。
bash复制# 连续 ping 30 次,适合观察稳定性
ping -c 30 www.example.com
# Windows 下不自动停止,用 Ctrl+C 结束
ping -t www.example.com
如果 ping 公网 IP 正常、ping 域名解析也正常,但网页打开还是慢,就用 traceroute 看路径。重点观察每一跳的时延和丢包:
bash复制traceroute -n www.example.com
tracert -d www.example.com
排障经验里有个经典误判:中间某个路由器显示 * * *,大家就以为是丢包。实际上很多运营商路由器出于性能考虑,不对超过 TTL 的包回 ICMP 超时消息,就会表现为星号,不代表链路中断。判断链路质量,要看目标节点之前最后一跳的最终结果,而不是被中间的星号吓到。还有,traceroute 的结果受路由策略影响,路径可能不对称,来回走的不是同一条链路,所以单向延迟不能直接等同于整条链路的故障。
4.3 ICMP 的安全隐患与处理原则
ICMP 虽然好用,但大量利用它做攻击的方式也很常见,比如 ICMP 洪水、Smurf 攻击、Ping of Death。很多安全基线会建议“禁 ping”,以减少被探测的可能性。我个人的态度是:外部入口禁 ping 可以,内部网络必须留出诊断能力。
防火墙规则的通行做法是:外部到内部的 ICMP 回显请求默认丢弃,但允许出方向的回显请求和入方向的回显应答、超时消息、目标不可达消息。这样你还能从内部 traceroute 出去,外部却不能轻易探测你的主机。生产服务器上如果担心 ICMP 重定向攻击,可以额外设置 net.ipv4.conf.all.accept_redirects=0 并关闭源路由选项。
5. CDN:把内容送到用户家门口
5.1 CDN 的加速原理:缓存、调度与回源
CDN(内容分发网络)本质上是一张大网,上面分布着大量边缘节点。用户请求资源时,DNS 或应用层调度会把他引导到离他最近、负载最低的节点,该节点如果缓存了资源就直接返回,没有缓存才回源站取。
完整流程大概是这样的:用户访问加速域名 → 本地 DNS 解析出 CDN 的 CNAME → CDN 的全局负载均衡(GSLB)根据用户 IP 归属地、运营商、节点负载,返回最优边缘节点 IP → 用户请求到边缘节点 → 边缘节点命中缓存则直接返回,未命中则回源站拉取并缓存。
这里有一个关键概念:CDN 不是把源站搬到各处,而是“缓存内容到边缘”。它能加速的就是可缓存的静态资源(图片、CSS、JS、视频切片)。动态请求、带用户登录态的接口、个性化页面,这些不适合普通 CDN 缓存,除非配套使用动态加速或边缘计算能力。
5.2 CDN 配置要点:缓存规则、回源协议与 HTTPS
接入 CDN 后,日常运维最常调的是三类配置:
- 缓存规则:按路径、文件类型、URL 参数设置 TTL。比如
/static/*缓存 30 天,.html缓存 10 秒,带参数的动态接口不缓存。建议给源站的静态资源加版本号,这样 CDN 内容更新时能通过 URL 变化强制回源。 - 回源协议:支持 HTTP 回源和 HTTPS 回源。回源走 HTTP 时源站压力大但有中间链路被劫持风险;全链路 HTTPS 更安全但回源性能稍差。一般至少保证用户到节点这段是 HTTPS,回源按业务敏感度选择。
- 回源 Host:源站上多个站点共用一个 IP 时,CDN 需要通过回源 Host 区分要访问哪个站。配置不对,页面会显示默认站点或证书不匹配。
还有一个常见问题:CDN 缓存了旧版本文件,用户强制刷新也没用。解决方法是配置“刷新缓存”或“预热”功能,CDN 控制台一般都有入口,提交 URL 后节点删除旧缓存或主动拉取新资源。
5.3 CDN 故障排查:命中率低、回源失败、内容污染
CDN 出问题时的排查,我总结成一张速查表,先看这里再动手:
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| 页面时好时坏 | 部分节点缓存过期、部分节点未刷新 | 对比不同地区访问,确认是否调度问题 |
| 命中率偏低 | 缓存规则不匹配、URL 带随机参数 | 调整缓存规则,归一化 URL 参数 |
| 回源失败 | 源站防火墙封了节点 IP、回源 Host 错误 | 检查源站访问日志,放行 CDN 节点 IP |
| 证书告警 | HTTPS 证书未上传或过期 | 检查节点证书和源站证书链 |
| 内容被篡改 | 回源链路被劫持、源站被入侵 | 开启全链路 HTTPS,加强源站防护 |
排查时务必保留“客户端 IP、访问 URL、报错截图、响应头信息”四个信息。CDN 大多支持在响应头里带 X-Cache: HIT/MISS 标记,看到 HIT 说明命中缓存,MISS 说明这次实际回源了。这是判断 CDN 是否真正生效最快的办法。
5.4 视频与直播场景:CDN 选路和优选脚本的边界
视频和直播是 CDN 的大客户,延迟和卡顿直接决定用户体验。视频网站常常用多码率切片、预加载、节点调度等手段降低卡顿。社区里流传的“CDN 优选脚本”,本质是帮你测试当前网络到不同 CDN 节点的速度和稳定性,然后自动改写本地 Hosts 或 DNS,让客户端强制走到更快节点。
这类脚本在合规范围里可以用于优化正常视频服务的观看体验,比如选择更快的运营商节点、避开拥堵时段。大家要注意的是:任何“优选”都要遵守服务条款,不要绕过地域限制或做超范围访问,否则轻则节点被封,重则有合规风险。我自己的习惯是优先使用服务商官方提供的调度策略,只有在官方效果不理想且仅用于改善自家业务的网络质量时,才考虑本地 DNS 或 Hosts 优化。
CDN 配置完后,压测很有必要。不要只在公司网络测,要分别从电信、联通、移动网络下做测试,看节点调度是否合理,时延是否真的有改善。有条件的话,用第三方拨测工具模拟多地域访问,这样才能发现部分区域节点服务异常的问题。
6. 常见问题与排查技巧实录
6.1 DNS 问题速查
日常里 DNS 相关的问题最多,我把排查过的典型问题直接列成一个速查表:
| 问题现象 | 原因 | 解决思路 |
|---|---|---|
| 解析结果不一致,时好时坏 | 多级缓存、不同 DNS 返回不同节点 | 用 dig @不同DNS 域名 对比,等待 TTL 过期 |
| 域名解析失败但 IP 能通 | DNS 服务器不可达或配置错误 | 换公共 DNS,检查防火墙 UDP/TCP 53 |
| 配置 DNS 后重启还原 | systemd-resolved 接管 | 用 netplan 或 NetworkManager 改 |
| Chrome 提示找不到 DNS,其他浏览器正常 | Chrome 自身缓存 | 清 chrome://net-internals/#dns |
| 内网域名解析到外网 IP | hosts 或 DNS 视图未隔离 | 部署 dnsmasq/bind 分域解析 |
| 域名解析到 CDN 节点但访问很慢 | 调度不准确、节点故障 | 联系 CDN 厂商调整调度,或本地换节点 |
6.2 TCP/UDP 连接问题与抓包入门
连接类问题里出现频率最高的是 TCP 连接超时和大量 TIME_WAIT、CLOSE_WAIT。前者看路由和防火墙丢包,后者看应用代码是否释放连接。用 ss 或 netstat 快速统计连接状态:
bash复制ss -ant | awk '{print $1}' | sort | uniq -c
如果 CLOSE_WAIT 数量持续上涨,别急着调内核参数,先查应用是哪个线程打开的连接没有关闭。Java 里就是连接池泄漏,Nginx 里则是 upstream 长连接配置和 keepalive 不匹配。抓包是定位这类问题的利器,Wireshark 抓个包看三次握手是否完成:如果只看到 SYN,没有 SYN+ACK,说明包没到服务端或被防火墙拦截;如果看到 SYN 重传多次,说明链路质量差或服务端队列满导致内核丢包。
UDP 的问题更难排查,因为丢了包没有重传,应用层大概率自己实现超时。这类场景我建议同时抓客户端和服务端两侧包,对比同一序号的数据是否到达,用时间戳看单程延迟。另外 UDP 数据包超过 MTU(常见 1500)时会触发 IP 分片,分片丢失会让整包无效。此时最优解法是应用层限制报文大小,或者在网络设备上调整 MTU。
6.3 我给新手的高效学习顺序
最后分享一套我复盘多年的学习顺序,按这套走,比“从教材第一章开始啃”快得多:
- 用 Wireshark 抓一次完整的 HTTP 请求,亲眼看到 TCP 三次握手、HTTP 请求和响应、TCP 挥手,建立“封装/解封装”的直觉。
- 用
ping、traceroute、dig三个命令做 10 组排障练习,直到你看到错误提示能猜到是网络层还是 DNS 层的问题。 - 配一台 dnsmasq 或 bind9,把内网域名解析跑通,理解 DNS 的递归、迭代和缓存。
- 部署一个带 CDN 的静态站点,配置缓存规则、回源协议、HTTPS,观察
X-Cache: HIT/MISS。 - 回归教材,把 OSI 七层一条条对照你抓到的报文,你会发现所有概念都被串起来了。
我每次带新人都是这个思路,最快一个月就能独立处理公司里八成网络问题。网络知识不是一扇门,而是一张网。你只要先从一条主路径走通,后面每学一个新协议,都是在往这张网上添新的节点,越学越清晰,越学越稳。
