执行 ping 命令时,网络到底发生了什么?
ping example.com 这条命令几乎人人敲过。
回车,几行 time=12.3 ms 滚出来,网络通了。
可中间这十几毫秒里,数据包到底走了哪些路、握了哪些手?
很多教程一句话带过:ping 用 ICMP 发个包,对面回个包,完事。
这说法不算错,但漏了一大半。
真实的链路里,DNS、ARP、路由表一个都不能少。下面按顺序拆。
ping 的本质是什么
ping 是一个网络连通性诊断工具,它的核心是 ICMP 协议的 Echo 机制。
源主机发一个 ICMP Echo Request(回显请求),目标主机收到后回一个 ICMP Echo Reply(回显应答)。
源主机根据发包和收包的时间差,算出往返时延(RTT,Round Trip Time),再统计丢了几个包。
注意一个常被忽略的点:ICMP 不是传输层协议。
它寄生在 IP 之上,IP 头里的协议号字段填 1 就表示载荷是 ICMP。
所以严格说,ping 没有用到 TCP 或 UDP,它直接跟 IP 打交道。
完整流程:从回车到结果
假设你敲的是 ping www.example.com,本机此前没访问过它。整个过程是这样的:
第一步,DNS 解析
输入的是域名,机器不认识,得先翻译成 IP。
系统发起 DNS 查询,把 www.example.com 换成类似 93.184.216.34 的地址。
如果你直接 ping IP,这一步跳过。
很多人调试时发现 ping 域名超时、ping IP 却通,问题往往就卡在 DNS,跟链路本身没关系。
第二步,构造 ICMP 报文
ping 程序拼出一个 ICMP Echo Request 报文,里面有几个关键字段:
- 类型(Type):Echo Request 为 8,Echo Reply 为 0
- 代码(Code):固定为 0
- 标识符(Identifier):通常是进程 ID,用来区分是哪个 ping 进程发的
- 序列号(Sequence):每发一个包加 1,用来配对请求和应答
- 数据区:包含发送时间戳和一段填充数据(Linux 默认填 56 字节)
序列号和标识符是配对的关键。
源主机靠它们认出「这个应答是回我刚才那个请求的」。
第三步,封装成 IP 包
ICMP 报文交给 IP 层,套上 IP 头:源 IP 是本机,目的 IP 是第一步解析出来的地址,协议号填 1,TTL 设个初始值(Linux 常见 64,Windows 常见 128)。
第四步,查路由表 + ARP 寻址
这一步是原文漏掉、却最容易出错的环节。
IP 包要发出去,得先知道下一跳是谁。
系统查路由表:目的 IP 跟本机在同一网段,就直接发给对方;不在同一网段(比如要访问公网),就发给默认网关。
但下一步是数据链路层,它认的是 MAC 地址不是 IP。
于是要用 ARP 协议,把「下一跳的 IP」翻译成「下一跳的 MAC」。
本机先查 ARP 缓存,没有就在局域网里广播一句「谁是 192.168.1.1?把 MAC 告诉我」,对应设备单播回复自己的 MAC。
IPv6 环境里这活儿由 NDP(邻居发现协议)干,原理类似。
第五步,封装以太网帧发出去
拿到下一跳 MAC 后,IP 包被封装成以太网帧,填上源 MAC、目的 MAC,从网卡发出。
注意目的 MAC 填的是下一跳(网关或对端),不是最终目标主机的 MAC——跨网段时你根本拿不到对方的 MAC。
第六步,逐跳转发
帧进入网络。
交换机按 MAC 转发,路由器按 IP 转发。
每经过一个路由器,TTL 减 1。
一旦 TTL 减到 0,包就被丢弃,该路由器回一个 ICMP 超时报文。
traceroute 正是利用这个机制,靠递增 TTL 把沿途每一跳探出来。
第七步,目标主机应答
目标主机收到 Echo Request,剥掉各层头部,看到这是个回显请求,于是构造一个 Echo Reply(类型 0),把原请求里的标识符、序列号、数据原样带回去,沿路径返回源主机。
第八步,计算并输出结果
源主机收到应答,用当前时间减去数据区里的时间戳,得到 RTT;
按序列号统计哪些包没回来,算出丢包率;
IP 头里的 TTL 还能反推大致经过了几跳。
最后这些数字打印到屏幕。
ping 到底用了哪些协议
原文列了三个协议,但描述不全也不够准。
按分层捋一遍更清楚:
| 协议 | 所在层 | 在 ping 里干什么 |
|---|---|---|
| DNS | 应用层 | 域名转 IP(直接 ping IP 时不涉及) |
| ICMP | 网络层 | 承载 Echo 请求与应答,是 ping 的核心 |
| IP | 网络层 | 封装 ICMP 报文,负责寻址和路由 |
| ARP / NDP | 链路层 | 把下一跳 IP 解析成 MAC 地址 |
| 以太网等 | 链路层 | 把 IP 包封装成帧,在物理介质上传输 |
把 ARP 单独拎出来说一句:它解析的是下一跳的 MAC,不是目标主机的 MAC。
同网段时下一跳就是对方,跨网段时下一跳是网关。这个区别很多人没分清。
几个绕不开的细节
ping 需要权限。
传统实现要用原始套接字(Raw Socket)来收发 ICMP,这通常需要 root 权限。
所以早年 Linux 上 ping 命令带 setuid 位。
现在不少系统改用 SOCK_DGRAM 的 ICMP 套接字,普通用户也能跑。
ping 不通不等于网络不通。
很多服务器、防火墙默认丢弃或限速 ICMP,纯属安全策略。
ping 超时,对方的 Web 服务可能好好的。
反过来 ping 通也只说明三层可达,应用层好不好得另测。
ping 测不了带宽和拥塞。
它只能告诉你「通不通」和「往返多久」,至于链路有多宽、丢包是偶发还是持续,得靠别的工具。我自己排查线上抖动时,一般 ping 看连通性、mtr 看逐跳丢包、iperf 压带宽,分开用。
常见问题
ping 用的是 TCP 还是 UDP?
都不是。
ping 用 ICMP,而 ICMP 直接构建在 IP 之上,跟 TCP、UDP 平级,不经过传输层。
所以 ping 没有端口的概念。
为什么 ping 域名超时,ping IP 却通?
大概率是 DNS 出了问题。
ping 域名要先做 DNS 解析,解析失败或解析到错误地址,自然不通;直接 ping IP 跳过解析,所以正常。
先检查 DNS 配置和 /etc/hosts。
TTL 是干什么的,能看出什么?
TTL 是 IP 包的「生存时间」,每过一个路由器减 1,减到 0 就被丢弃,防止包在网络里无限打转。
看返回包的 TTL 能粗略反推经过了几跳,也能猜对方系统(Linux 初始 64、Windows 初始 128)。
ping 不通是不是网络一定有问题?
不一定。
对方可能主动屏蔽了 ICMP,这是常见的安全做法。
ping 不通时,网页、SSH 等服务可能照样能用,别只凭 ping 下结论。
ARP 在 ping 里起什么作用?
ARP 负责把「下一跳的 IP 地址」解析成「MAC 地址」,因为链路层只认 MAC。
没有 ARP,IP 包封装不成以太网帧,根本发不出去。
写在最后
ping 看着简单,背后却串起了从应用层到链路层的一整条链路。
理解这条链路最大的好处是:出问题时知道往哪儿查——是 DNS、是路由、还是对方在丢 ICMP,而不是干瞪着 Request timeout 发愁。
以上流程基于常见的 IPv4、以太网环境整理,不同操作系统和网络环境的实现细节会有差异。
如果你在排查时遇到过更奇怪的 ping 现象,欢迎在评论区聊聊~
版权声明
未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!
本文原文链接: https://fiveyoboy.com/articles/what-happens-when-you-run-ping/
备用原文链接: https://blog.fiveyoboy.com/articles/what-happens-when-you-run-ping/