- 文档
- 教程
- 知识库
【免费下载链接】CS-Base
图解计算机网络、操作系统、计算机组成、数据库,共 1000 张图 + 50 万字,破除晦涩难懂的计算机基础知识,让天下没有难懂的八股文!🚀 在线阅读:https://xiaolincoding.com
导读:本文是 CS-Base《图解网络》"IP 篇"的核心实战之一(network/4_ip/ping_lo.md),从"拔掉网线后 ping 127.0.0.1 依然通"这个经典现象出发,完整拆解回环地址的本质、ping 与普通 TCP 发包的底层差异、数据在本机"假网卡"上的收发路径,以及 127.0.0.1、localhost、0.0.0.0 三者到底有什么区别。读完你将掌握:为什么断网不影响回环通信、如何用抓包验证本机 IP 与回环地址的等效性,以及服务器监听 0.0.0.0 的真实含义,并能在面试八股与日常排障中直接复用这套分析思路。
实验开场:拔掉网线,ping 127.0.0.1
先做一个最直接的实验:把网线拔掉、彻底断网,然后在终端执行:
$ ping 127.0.0.1 PING 127.0.0.1 (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.080 ms 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.093 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.074 ms 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.079 ms 64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.079 ms ^C --- 127.0.0.1 ping statistics --- 5 packets transmitted, 5 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.074/0.081/0.093/0.006 ms结论很明确:断网状态下,ping 127.0.0.1依然能通,5 个包全部收到、零丢包,RTT 也只有零点几毫秒。
但这不代表不用交网费就能上网。答案的关键在于:回环地址(loopback address)的通信路径根本不经过"真网卡",数据包在本机内部转了个圈就回来了。下面逐层拆解背后的原理。
什么是 127.0.0.1:人为规定的回环地址
IPv4 地址的位宽与书写方式
127.0.0.1是一个IPv4 地址。IPv4 地址由 32 位正整数组成(4 个字节),人类为了便于记忆采用点分十进制表示:32 位每 8 位一组、共分 4 组,组间用.隔开,每组再转成十进制。关于 IPv4 地址分类(A/B/C/D/E)、子网划分、CIDR 等完整背景,见同目录的 IP 基础知识全家桶。
127 网段都是回环地址
以 127 开头的地址都属于回环地址,是 IPv4 的特殊地址段。这是人为规定,不需要问"为什么"。而127.0.0.1只是众多回环地址中的一个,之所以默认是127.0.0.1而不是127.0.0.2,是因为操作系统源码里就是这么定义的,同样"没什么道理"。Linux 内核头文件中的定义如下:
/* Address to loopback in software to local host. */ #define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */0x7f000001正是127.0.0.1的十六进制形态:0x7f= 127,0x00= 0,0x00= 0,0x01= 1。
IPv4 地址枯竭与 IPv6 的诞生
IPv4 地址是 32 位的,2 的 32 次方约40 多亿,而地球人口早已超过 76 亿,加上每台设备往往不止一块网卡,IPv4 地址实际上早已被分配完毕,这也是必须引入 NAT、CIDR 等缓解技术的原因(详见 IP 基础知识全家桶 中的 NAT 与无分类地址小节)。
于是有了 IPv6:地址长度128 位,2 的 128 次方约等于 10 的 38 次方——"地球沙子的数量约 10 的 23 次方",IPv6 的地址量可以认为用不完。
两种地址的书写差异:
- IPv4:32 位以 8 位为一组,共 4 组,用
.隔开(点分十进制); - IPv6:128 位以 16 位为一组,共 8 组,用
:隔开;如果某段全是 0,可以把连续的 0 省略,用::表示,但一个 IPv6 地址中只允许出现一次::。
IPv6 下的回环地址:::1
在 IPv4 中回环地址是127.0.0.1,在 IPv6 中则表示为::1——中间省略了连续的多组 0,最后一位是 1。之所以不是 7 个冒号,而是 2 个冒号::,正是上面说的"一个 IPv6 地址中只允许出现一次两个连续的冒号"的规则。
对应的 ping 命令也要变化:
- IPv4 下用
ping 127.0.0.1; - IPv6 下用
ping6 ::1。
佐证:在 IP 基础知识全家桶 的"环回地址是不会流向网络"一节中明确写到:计算机使用特殊的 IP 地址
127.0.0.1作为环回地址,与之具有相同意义的还有localhost主机名,使用这个 IP 或主机名时,数据包不会流向网络。
什么是 ping:应用层命令 + 网络层 ICMP
ping是应用层命令,它和游戏、聊天软件处于同一层。区别在于:聊天软件功能复杂(收发消息、点赞等),而 ping 功能很简单——尝试向目标机器发送一个很小的消息,判断目的机器是否可达,也就是判断网络是否连通。
ping 的底层使用的是网络层的ICMP 协议(Internet Control Message Protocol,互联网控制报文协议)。虽然 ICMP 和 IP 都属于网络层协议,但ICMP 报文实际上是利用 IP 协议进行传输的——ICMP 报文被封装在 IP 数据包里,IP 首部中协议号字段为 1 即表示携带的是 ICMP 报文。
ICMP 报文按类型字段分为两大类(完整讲解见 ping 的工作原理):
- 查询报文类型:用于诊断,如回送请求(Echo Request,类型 8)与回送应答(Echo Reply,类型 0)——正是 ping 使用的消息;相比原生 ICMP,还多了标识符(用于区分是哪个应用程序发的包,常取进程 PID)和序号(从 0 开始,每次发送加 1,用于确认是否丢包),并在选项数据中存放发送时间用于计算往返时间 RTT;
- 差错报文类型:用于通知出错原因,如目标不可达(类型 3,代码 0/1/2/3/4 分别表示网络不可达、主机不可达、协议不可达、端口不可达、需分片但设置了不分片位)、原点抑制(类型 4)、重定向(类型 5)、超时(类型 11,对应 TTL 递减为 0)。
所以,简单理解 ping 某个 IP,就是往某个 IP 地址发个 ICMP 消息并等待回执。
TCP 发数据和 ping 的区别:同一套流程,不同的 socket 类型
一般情况下我们使用 TCP 进行网络数据传输。把它和 ping 横向对比,能直观看出二者的共性与差异。
共性:都从应用层走向网卡
以聊天软件用 TCP 发消息为例,要发消息就得先知道"往哪发"。Linux 里"万物皆文件",发送目的地也是一个文件,这里引出socket 概念。使用 socket 的第一步是创建它:
socket(AF_INET, SOCK_STREAM, 0);AF_INET:表示将使用IPv4 里 host:port 的方式解析后面输入的网络地址;SOCK_STREAM:使用面向字节流的 TCP 协议,工作在传输层。
创建好 socket 后,就可以把要传输的数据写到这个"文件"里。调用 socket 的sendto接口时,进程会从用户态进入内核态,最终调用到sock_sendmsg方法。随后数据依次:进入传输层带上TCP 头→ 网络层带上IP 头→ 数据链路层带上MAC 头→ 进入网卡的发送队列 ring buffer,顺着网卡发出。
这一"应用层 → 传输层 → 网络层 → 数据链路层 → 网卡"的完整链路,在 Linux 系统是如何收发网络包的? 中有系统讲解。
差异:ping 使用原始套接字,工作在网络层
回到 ping,整个过程与 TCP 发数据基本类似,差异主要在于创建 socket 的参数:
socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)SOCK_RAW是原始套接字,工作在网络层,因此构建 ICMP(网络层协议)数据再合适不过;IPPROTO_ICMP明确指定协议为 ICMP。
ping 进入内核态后最后调用的同样是sock_sendmsg方法:进入网络层后加上ICMP 头 + IP 头,数据链路层加上MAC 头,也是顺着网卡发出。因此本质上,ping 和普通应用发消息在程序流程上没太大差别。
这也解释了为什么排查网络问题时,第一反应总是"你能 ping 通吗":ping 相当于自己组了一个数据包,让系统按其他软件发数据的路径往外发一遍,能通就说明其他软件发数据也能通。完整的 ICMP 请求/应答报文交互细节见 ping 的工作原理。
为什么断网了还能 ping 通 127.0.0.1:本地"假网卡"的完整路径
前面提到,有网的情况下 ping 最后是通过真网卡把数据发送出去的。那么断网时网卡已经不工作了,ping 回环地址却一切正常,它的数据到底走的是哪条路?
网络层:路由表决定走哪块网卡
从应用层到传输层再到网络层,这段路径跟 ping 外网时几乎一样。到了网络层,系统会根据目的 IP 在路由表中查询对应的路由信息,而路由信息中就包含选择哪块网卡发出消息:
- 当发现目标 IP 是外网 IP时,会从"真网卡"发出;
- 当发现目标 IP 是回环地址时,就会选择本地网卡(loopback 接口)。
路由表按网络地址匹配目标、遵循最长匹配原则的机制,在 IP 基础知识全家桶 的"IP 地址与路由控制"一节有详细说明。
本地网卡:没有 ring buffer 的"假网卡"
本地网卡其实是个**"假网卡"**,它不像"真网卡"那样有发送队列 ring buffer。它的工作方式是:
- "假网卡"把数据推到一个叫
input_pkt_queue的链表中——这个链表是所有网卡共享的,上面挂着发给本机的各种消息; - 消息进入链表后,会触发一次软中断;
- 专门处理软中断的内核线程ksoftirqd收到软中断后,立马从链表里取出消息;
- 然后顺着数据链路层、网络层等层层往上传递,最后把数据交给应用程序。
深度佐证:在 什么是软中断? 中可以看到,软中断以内核线程方式执行,每个 CPU 对应一个软中断内核线程,名字通常是
ksoftirqd/CPU 编号(如 0 号 CPU 对应ksoftirqd/0);网络接收对应的软中断类型是NET_RX,可以通过/proc/softirqs查看各 CPU 的软中断累计次数,用ps命令可以看到中括号内的内核线程 ksoftirqd。
结论:整条路径根本没出网络
ping 回环地址,以及通过 TCP 等各种协议发送数据到回环地址,走的都是上面这条路径——从发到收,全程没有经过"真网卡"。
之所以 127.0.0.1 叫本地回环地址,可以理解为:消息发到这个地址上,就不会出网络,在本机打一个转就又回来了。所以断网,依然能 ping 通 127.0.0.1。同时这也说明:能 ping 通 127.0.0.1 只代表本机网络协议栈工作正常,与是否缴纳网费、能否访问外网毫无关系。
ping 回环地址和 ping 本机地址有什么区别:抓包验证,二者等价
很多人有一个直觉:ping 本机 IP(真网卡的地址)会从"真网卡"出去,遇到第一个路由器再绕回来。这个说法对不对?用ifconfig和抓包来验证。
在 mac 上执行ifconfig:
$ ifconfig lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 inet 127.0.0.1 netmask 0xff000000 ... en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 inet 192.168.31.6 netmask 0xffffff00 broadcast 192.168.31.255 ...- lo0:本地回环接口,对应地址就是前面提到的
127.0.0.1,也就是回环地址; - en0:本机第一块真网卡(Linux 下通常叫 eth0),对应 IP 地址
192.168.31.6,即本机 IP。
接下来对两种 ping 分别抓包观察数据流经的接口:
ping 127.0.0.1:相关网络数据走的都是lo0;ping 192.168.31.6(本机地址):抓包结果与上面相同,同样走的是lo0。
也就是说,只要走了本地回环接口,数据都不会发送到网络中,在本机网络协议栈里兜一圈就发回来了。结论非常干脆:
ping 回环地址和 ping 本机地址没有区别——本机 IP 的数据包同样会在"即将出网卡前"被路由选择逻辑拉回本地回环路径,而非真的发送到物理网络中。
127.0.0.1、localhost、0.0.0.0 有区别吗:面试常客的完整辨析
用 nginx 做实验时,会发现访问127.0.0.1:80、localhost:80、0.0.0.0:80以及本机 IP 的 80 端口,都能看到 nginx 欢迎页,容易让人误以为这几个地址完全一样。但本质上是有区别的。
localhost:是域名,不是 IP
localhost不叫 IP,它是一个域名,形式和baidu.com一样。只不过操作系统默认会把localhost解析为127.0.0.1,并且这个映射可以在/etc/hosts文件中修改。
所以:默认情况下,使用localhost和使用127.0.0.1确实没区别——因为二者最终解析到同一个回环地址;但只要改掉/etc/hosts里的映射,localhost 的含义就会随之改变。
0.0.0.0:无效的目标地址,却是万能的服务监听地址
先看ping 0.0.0.0,它会失败:
$ ping 0.0.0.0 PING 0.0.0.0 (0.0.0.0): 56 data bytes ping: sendto: No route to host ping: sendto: No route to host因为0.0.0.0在 IPv4 中表示的是无效的目标地址——没有任何主机以它作为自己的地址,路由表里自然找不到去往它的路由。
但它有另一个重要用途:服务端监听。我们启动服务器时,一般会listen一个 IP 和端口,等待客户端连接:
/* Address to accept any incoming messages. */ #define INADDR_ANY ((unsigned long int) 0x00000000) /* 0.0.0.0 */如果此时listen的是0.0.0.0,那么它表示本机上的所有 IPv4 地址。举个例子:刚才提到的127.0.0.1和192.168.31.6都是本机的 IPv4 地址,如果服务监听0.0.0.0,那么用上面两个地址都能访问到这个服务器。反过来,如果只 listen 了某个具体地址(如 127.0.0.1),那只有该地址能访问,其他地址访问会被拒绝。
佐证:在 服务端没有 listen,客户端发起连接建立,会发生什么? 的示例代码中,服务端正是用
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);绑定0.0.0.0,实现对本机所有 IPv4 地址 + 端口的监听。
而作为客户端,connect时不能使用0.0.0.0,必须指明要连接哪个具体的服务器 IP。
总结:三个必须记住的结论
127.0.0.1是回环地址;localhost是域名,默认情况下解析结果等于127.0.0.1(可通过/etc/hosts修改)。- ping 回环地址和 ping 本机地址是一样的:都走 lo0 这个"假网卡",都会经过网络层和数据链路层等逻辑,最后在"快要出网卡前"狠狠拐了个弯,把数据插入共享链表
input_pkt_queue,触发软中断,由内核线程ksoftirqd执行"收数据"的逻辑——压根就不出网络。所以断网了也能 ping 通回环地址。 - 如果服务器
listen的是0.0.0.0(即INADDR_ANY),那么用127.0.0.1和本机地址都可以访问到服务;而0.0.0.0不能作为 ping 的目标,也不能作为客户端 connect 的目标。
面试遇到"断网了还能 ping 通 127.0.0.1 吗?""127.0.0.1 和 localhost 有什么区别?""服务器为什么要监听 0.0.0.0?"这类问题时,只要抓住一条主线即可答全:回环通信全程在本机协议栈内完成,不经过物理网卡——这正是断网可通、localhost 等价于 127.0.0.1、0.0.0.0 只是"通配所有本机地址"的根本原因。
延伸阅读(本仓库关联章节)
- IP 基础知识全家桶:IP 分类、CIDR、子网划分、环回地址不会流向网络、NAT 等完整背景
- ping 的工作原理:ICMP 查询/差错报文类型、ping 与 traceroute 的完整收发流程
- 什么是软中断?:ksoftirqd 内核线程、NET_RX 软中断、/proc/softirqs 排查方法
- Linux 系统是如何收发网络包的?:应用层到网卡的完整收发链路
- 服务端没有 listen,客户端发起连接建立,会发生什么?:
INADDR_ANY绑定与监听语义的代码示例 - 《图解网络》目录与阅读指引:查看本书完整章节结构
- 文档
- 教程
- 知识库
【免费下载链接】CS-Base
图解计算机网络、操作系统、计算机组成、数据库,共 1000 张图 + 50 万字,破除晦涩难懂的计算机基础知识,让天下没有难懂的八股文!🚀 在线阅读:https://xiaolincoding.com
相关推荐
Raylib 跑通全路径:源码构建 + CMake 接入 + 5 个高频报错解法
Raylib 跑通全路径:源码构建 + CMake 接入 + 5 个高频报错解法 raylib 编译报错里最高频的是 undefined reference t
游戏开发图形学3D渲染CS-Base 图解网络:键入网址到网页显示,期间发生了什么?——HTTP、DNS、TCP、IP、MAC 全链路拆解
CS Base 图解网络:键入网址到网页显示,期间发生了什么?——HTTP、DNS、TCP、IP、MAC 全链路拆解 本篇技术指南以 CS Base(图解计算机
文档教程知识库Homebrew 包管理器指南:一条命令装好软件,Brewfile 一键还原整台机器
Homebrew 包管理器指南:一条命令装好软件,Brewfile 一键还原整台机器 Homebrew 包管理器把装软件、管版本、跑服务这几件琐事全接走了:命令
CLI包管理器
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考