断网了,还能 ping 通 127.0.0.1 吗?
网通不通, ping 一下就知道了。
可能看到标题,你就知道答案了。你了解背后的原因吗?
那如果把 127.0.0.1 换成 0.0.0.0 或 localhost 会怎么样呢?这几个有什么区别吗?
话不多说,直接拔掉网线,断网。
然后在控制台输入 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 是能 ping 通的。
其实这篇文章看到这里,标题前半个问题已经被回答了。但是我们可以再想深一点。
为什么断网了还能 ping 通 127.0.0.1 呢?
不懂的同学看了就懂了,懂的看了就当查漏补缺吧。
什么是 127.0.0.1
首先,这是个 IPv4 地址。
IPv4 地址有 32 位,一个字节有 8 位,共 4 个字节。
其中127 开头的都属于回环地址,也是 IPv4 的特殊地址,没什么道理,就是人为规定的。
而 127.0.0.1 是众多回环地址中的一个。之所以不是 127.0.0.2 ,而是 127.0.0.1,是因为源码里就是这么定义的,也没什么道理。
/* Address to loopback in software to local host. */
#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */

回环地址
IPv4 的地址是 32 位的,2 的 32 次方,大概是 40 + 亿。地球光人口就 76 亿了,40 亿 IP 这点量,远远不够用,实际上IP 也确实用完了。
所以就有了 IPv6, IPv6 的地址是 128 位的,大概是 2 的 128 次方≈10 的 38 次方。据说地球的沙子数量大概是10 的 23 次方,所以 IPv6 的 IP 可以认为用不完。
IPv4 以 8 位一组,每组之间用 . 号隔开。
IPv6 以 16 位为一组,每组之间用 : 号隔开。如果全是 0,那么可以省略为 :: 号。

IPv6 回环地址
在 IPv4 下的回环地址是 127.0.0.1,在 IPv6 下,表达为 ::1 。中间把连续的 0给省略了,之所以不是7 个 冒号,而是2 个冒号:, 是因为一个 IPv6 地址中只允许出现⼀次两个连续的冒号。
多说一句:在 IPv4 下用的是ping 127.0.0.1命令。在 IPv6 下用的是ping6 ::1命令。
什么是 ping
ping 是应用层命令,可以理解为它跟游戏或者聊天软件属于同一层。只不过聊天软件可以收发消息,还能点个赞什么的,有很多复杂的功能。而 ping 作为一个小软件,它的功能比较简单,就是尝试发送一个小小的消息到目标机器上,判断目的机器是否可达,其实也就是判断目标机器网络是否能连通。
ping 应用的底层,用的是网络层的 ICMP 协议。

IP 和 ICMP 和 Ping 所在分层
虽然 ICMP 协议和 IP 协议都属于网络层协议,但其实`ICMP 也是利用了 IP 协议进行消息的传输。

ip 和 icmp 的关系
所以,在这里完全可以简单地理解为 ping 某个 IP 就是往某个 IP 地址发个消息。
TCP 发数据和 ping 的区别
一般情况下,我们会使用 TCP 进行网络数据传输,那么可以看下它和 ping 的区别。

ping 和普通发消息的关系
ping 和其他应用层软件都属于应用层。
那么我们横向对比一下,比方说聊天软件,如果用的是 TCP 的方式去发送消息。
为了发送消息,那就得先知道往哪发。linux 里万物皆文件,那你要发消息的目的地,也是个文件,这里就引出了 socket 的概念。
要使用 socket , 那么首先需要创建它。
在 TCP 传输中创建的方式是 socket (AF_INET, SOCK_STREAM, 0);,其中 AF_INET 表示将使用 IPv4 里host:port的方式去解析待会你输入的网络地址。SOCK_STREAM 是指使用面向字节流的 TCP 协议,工作在传输层。
创建好了 socket 之后,就可以愉快的把要传输的数据写到这个文件里。调用 socket 的 sendto 接口的过程中进程会从用户态进入到内核态,最后会调用到 sock_sendmsg 方法。
然后进入传输层,带上 TCP 头。网络层带上 IP 头,数据链路层带上 MAC 头等一系列操作后。进入网卡的发送队列 ring buffer,顺着网卡就发出去了。
回到 ping , 整个过程也基本跟 TCP 发数据类似,差异的地方主要在于,创建 socket 的时候用的是 socket (AF_INET,SOCK_RAW,IPPROTO_ICMP),SOCK_RAW 是原始套接字 ,工作在网络层, 所以构建 ICMP(网络层协议)的数据,是再合适不过了。
ping 在进入内核态后最后也是调用的 sock_sendmsg 方法,进入到网络层后加上ICMP 和 IP 头后,数据链路层加上MAC 头,也是顺着网卡发出。因此,本质上 ping 跟普通应用发消息在程序流程上没太大差别。
这也解释了**为什么当你发现怀疑网络有问题的时候,别人第一时间是问你能 ping 通吗?**因为可以简单理解为 ping 就是自己组了个数据包,让系统按着其他软件发送数据的路径往外发一遍,能通说明其他软件发的数据也能通。
为什么断网了还能 ping 通 127.0.0.1
前面提到,有网的情况下,ping 最后是通过网卡将数据发送出去的。
那么断网的情况下,网卡已经不工作了,ping 回环地址却一切正常,我们可以看下这种情况下的工作原理。

ping 回环地址
从应用层到传输层再到网络层。这段路径跟 ping 外网的时候是几乎是一样的。到了网络层,系统会根据目的 IP,在路由表中获取对应的路由信息,而这其中就包含选择哪个网卡把消息发出。
当发现目标 IP 是外网 IP时,会从 “真网卡” 发出。
当发现目标 IP 是回环地址时,就会选择本地网卡。
本地网卡,其实就是个"假网卡",它不像 “真网卡” 那样有个 ring buffer 什么的,“假网卡” 会把数据推到一个叫 input_pkt_queue 的链表中。这个链表,其实是所有网卡共享的,上面挂着发给本机的各种消息。消息被发送到这个链表后,会再触发一个软中断。
专门处理软中断的工具人 “ksoftirqd”(这是个内核线程),它在收到软中断后就会立马去链表里把消息取出,然后顺着数据链路层、网络层等层层往上传递最后给到应用程序。
ping 回环地址和通过 TCP 等各种协议发送数据到回环地址都是走这条路径。整条路径从发到收,都没有经过 “真网卡”。之所以 127.0.0.1 叫本地回环地址,可以理解为,消息发出到这个地址上,就不会出网络,在本机打个转就又回来了。所以断网,依然能 ping 通 127.0.0.1。
ping 回环地址和 ping 本机地址有什么区别
我们在 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,也就是回环地址。
和 eth0,表示本机第一块网卡,对应的 IP 地址是192.168.31.6,管它叫本机 IP。
之前一直认为 ping 本机 IP 的话会通过 “真网卡” 出去,然后遇到第一个路由器,再发回来到本机。
为了验证这个说法,可以进行抓包,但结果跟上面的说法并不相同。

ping 127.0.0.1

ping 本机地址
可以看到 ping 本机 IP 跟 ping 回环地址一样,相关的网络数据,都是走的 lo0,本地回环接口,也就是前面提到的"假网卡"。
只要走了本地回环接口,数据都不会发送到网络中,在本机网络协议栈中兜一圈,就发回来了。因此ping 回环地址和 ping 本机地址没有区别。
127.0.0.1 和 localhost 以及 0.0.0.0 有区别吗
以前第一次用 nginx 的时候,发现用这几个 IP,都能正常访问到 nginx 的欢迎网页。一度认为这几个 IP 都是一样的。

访问 127.0.0.1:80

访问 localhost:80

访问 0.0.0.0:80

访问本机的 IP 地址
但本质上还是有些区别的。
首先 localhost 就不叫 IP,它是一个域名,就跟 "baidu.com", 是一个形式的东西,只不过默认会把它解析为 127.0.0.1 ,当然这可以在 /etc/hosts 文件下进行修改。
所以默认情况下,使用 localhost 跟使用 127.0.0.1 确实是没区别的。
其次就是 0.0.0.0,执行 ping 0.0.0.0 ,是会失败的,因为它在 IPv4 中表示的是无效的目标地址。
$ 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
但它还是很有用处的,回想下,我们启动服务器的时候,一般会 listen 一个 IP 和端口,等待客户端的连接。
如果此时 listen 的是本机的 0.0.0.0 , 那么它表示本机上的所有 IPv4 地址。
/* Address to accept any incoming messages. */
#define INADDR_ANY ((unsigned long int) 0x00000000) /* 0.0.0.0 */
举个例子。刚刚提到的 127.0.0.1 和 192.168.31.6 ,都是本机的 IPv4 地址,如果监听 0.0.0.0 ,那么用上面两个地址,都能访问到这个服务器。
当然, 客户端 connect 时,不能使用 0.0.0.0 。必须指明要连接哪个服务器 IP。
总结
-
127.0.0.1是回环地址。localhost是域名,但默认等于127.0.0.1。 -
ping回环地址和ping本机地址,是一样的,走的是lo0 “假网卡”,都会经过网络层和数据链路层等逻辑,最后在快要出网卡前狠狠拐了个弯, 将数据插入到一个链表后就软中断通知ksoftirqd来进行收数据的逻辑,压根就不出网络。所以断网了也能ping通回环地址。 -
如果服务器
listen的是0.0.0.0,那么此时用127.0.0.1和本机地址都可以访问到服务。
Ping 原理解析:基于 ICMP 协议的网络诊断工具
小林 coding 于 2020-03-25 22:43:00 发布
前言
在日常网络使用或工作场景中,判断与目标网络是否畅通时,ping 命令是最为常用的工具之一。然而,ping 究竟是如何工作的呢?本文将深入剖析其原理,帮助读者全面理解。
IP 协议的助手 —— ICMP 协议
ping 基于 ICMP 协议运行,因此,理解 ping 的工作机制,需先熟悉 ICMP 协议。
ICMP
ICMP 全称为 Internet Control Message Protocol,即互联网控制报文协议。其核心在于 “控制”,网络数据包在复杂的网络环境中传输时,常面临各类问题。此时,需通过传出消息报告问题,以便调整传输策略,实现对网络状况的有效控制。
ICMP 功能
ICMP 的主要功能涵盖:确认 IP 包是否成功送达目标地址、报告 IP 包在发送过程中被废弃的原因,以及为改善网络设置提供信息等。在 IP 通信中,若某个 IP 包因特定原因未能抵达目标地址,ICMP 负责通知发送方具体原因。
例如,主机 A 向主机 B 发送数据包,若途中路由器 2 因某种原因未能发现主机 B,路由器 2 会向主机 A 发送 ICMP 目标不可达数据包,告知发往主机 B 的包未能成功传输。ICMP 的通知消息借助 IP 进行发送,从路由器 2 返回的 ICMP 包,会依照常规路由控制,先经过路由器 1,再转发给主机 A。主机 A 收到该 ICMP 包后,解析其首部和数据域,即可得知问题的具体原因。
ICMP 包头格式
ICMP 报文封装在 IP 包内,工作于网络层,是 IP 协议的辅助协议。

ICMP 包头的 类型 字段,大致可分为两类:
- 用于诊断的查询消息,即「查询报文类型」;
- 通知出错原因的错误消息,即「差错报文类型」。

查询报文类型
回送消息 —— 类型 0 和 8
回送消息用于主机或路由器之间的通信,判断所发送的数据包是否成功到达对端,ping 命令即基于此消息实现。

可向对端主机发送 回送请求 消息(ICMP Echo Request Message,类型 8),也能接收对端主机返回的 回送应答 消息(ICMP Echo Reply Message,类型 0)。

相比原生的 ICMP,该消息多了两个字段:
- 标识符:用于区分是哪个应用程序发送的 ICMP 包,例如可用进程
PID作为标识符; - 序号:序列号从
0开始,每发送一次新的回送请求就递增1,可用于确认网络包是否丢失。
在 选项数据 中,ping 还会记录发送请求的时间值,以计算往返时间,反映路程长短。
差错报文类型
以下介绍几个常用的 ICMP 差错报文示例:
- 目标不可达消息 —— 类型为
3; - 原点抑制消息 —— 类型
4; - 重定向消息 —— 类型
5; - 超时消息 —— 类型
11。
目标不可达消息(Destination Unreachable Message) —— 类型为 3
当 IP 路由器无法将 IP 数据包发送到目标地址时,会向发送端主机返回目标不可达的 ICMP 消息,并在该消息中显示不可达的具体原因,原因记录在 ICMP 包头的 代码 字段。发送端主机由此可了解此次发送不可达的具体原因。
举例 6 种常见的目标不可达类型的 代码:

- 网络不可达代码为
0 - 主机不可达代码为
1 - 协议不可达代码为
2 - 端口不可达代码为
3 - 需要进行分片但设置了不分片位代码为
4
为了给大家说清楚上面的目标不可达的原因,以送外卖场景进行类比:

a. 网络不可达代码为 0
- 外卖版本:小林第一次送外卖时,小区里只有 A 和 B 区两栋楼,但送餐地址写的是 C 区楼,小林表示找不到这个地方。
- 正常版本:IP 地址由网络号和主机号组成,当路由器中的路由表匹配不到接收方 IP 的网络号,就通过 ICMP 协议以 网络不可达(
Network Unreachable)的原因告知主机。随着网络发展,自从不再有网络分类以后,网络不可达也渐渐不再使用了。
b. 主机不可达代码为 1
- 外卖版本:小林第二次送外卖时,这次小区有 5 层楼高的 C 区楼了,找到地方了,但送餐地址写的是 C 区楼 601 号房 ,说明找不到这个房间。
- 正常版本:当路由表中没有该主机的信息,或者该主机没有连接到网络,那么会通过 ICMP 协议以 主机不可达(
Host Unreachable)的原因告知主机。
c. 协议不可达代码为 2
- 外卖版本:小林第三次送外卖时,这次小区有 C 区楼,也有 601 号房,找到地方了,也找到房间了,但是一开门人家是外国人说的是英语,我说的是中文!语言不通,外卖送达失败~
- 正常版本:当主机使用 TCP 协议访问对端主机时,能找到对端的主机了,可是对端主机的防火墙已经禁止 TCP 协议访问,那么会通过 ICMP 协议以 协议不可达 的原因告知主机。
d. 端口不可达代码为 3
- 外卖版本:小林第四次送外卖时,这次小区有 C 区楼,也有 601 号房,找到地方了,也找到房间了,房间里的人也是说中文的人了,但是人家说他要的不是外卖,而是快递。
- 正常版本:当主机访问对端主机 8080 端口时,这次能找到对端主机了,防火墙也没有限制,可是发现对端主机没有进程监听 8080 端口,那么会通过 ICMP 协议以 端口不可达 的原因告知主机。
e. 需要进行分片但设置了不分片位代码为 4
- 外卖版本:小林第五次送外卖时,这次是个吃播博主点了 100 份外卖,但是吃播博主要求一次性要把全部外卖送达,小林的一台电动车装不下呀,这样就没办法送达了。
- 正常版本:发送端主机发送 IP 数据报时,将 IP 首部的 分片禁止标志位 设置为
1。根据这个标志位,途中的路由器遇到超过 MTU 大小的数据包时,不会进行分片,而是直接抛弃。随后,通过一个 ICMP 的不可达消息类型,代码为 4 的报文,告知发送端主机。
原点抑制消息(ICMP Source Quench Message) —— 类型 4
在使用低速广域线路的情况下,连接 WAN 的路由器可能会遇到网络拥堵的问题。ICMP 原点抑制消息的目的就是 为了缓和这种拥堵情况。
当路由器向低速线路发送数据时,其发送队列的缓存变为零而无法发送出去时,可以向 IP 包的源地址发送一个 ICMP 原点抑制消息。
收到这个消息的主机借此了解在整个线路的某一处发生了拥堵的情况,从而增大 IP 包的传输间隔,减少网络拥堵的情况。然而,由于这种 ICMP 可能会引起不公平的网络通信,一般不被使用。
重定向消息(ICMP Redirect Message) —— 类型 5
如果路由器发现发送端主机使用了「不是最优」的路径发送数据,那么它会返回一个 ICMP 重定向消息 给这个主机。
在这个消息中包含了 最合适的路由信息和源数据。这主要发生在路由器持有更好的路由信息的情况下。路由器会通过这样的 ICMP 消息告知发送端,让它下次发给另外一个路由器。
好比,小林本可以过条马路就能到的地方,但小林不知道,所以绕了一圈才到,后面小林知道后,下次小林就不会再绕一圈了。
超时消息(ICMP Time Exceeded Message) —— 类型 11
IP 包中有一个字段叫做 TTL (Time To Live,生存周期),它的 值随着每经过一次路由器就会减 1,直到减到 0 时该 IP 包会被丢弃。
此时,路由器将会发送一个 ICMP 超时消息 给发送端主机,并通知该包已被丢弃。
设置 IP 包生存周期的主要目的,是为了在路由控制遇到问题发生循环状况时,避免 IP 包无休止地在网络上被转发。

此外,有时可以用 TTL 控制包的到达范围,例如设置一个 较小的 TTL 值。
ping —— 查询报文类型的使用
接下来,我们重点来看 ping 的 发送和接收过程。
同个子网下的主机 A 和 主机 B,主机 A 执行 ping 主机 B 后,我们来看看其间发送了什么?

ping 命令执行的时候,源主机首先会构建一个 ICMP 回送请求消息 数据包。
ICMP 数据包内包含多个字段,最重要的是两个:
- 第一个是 类型,对于回送请求消息而言该字段为
8; - 另外一个是 序号,主要用于区分连续 ping 的时候发出的多个数据包。
每发出一个请求数据包,序号会自动加 1。为了能够计算往返时间 RTT,它会在报文的数据部分插入发送时间。

然后,由 ICMP 协议将这个数据包连同地址 192.168.1.2 一起交给 IP 层。IP 层将以 192.168.1.2 作为 目的地址,本机 IP 地址作为 源地址,协议 字段设置为 1 表示是 ICMP 协议,再加上一些其他控制信息,构建一个 IP 数据包。

接下来,需要加入 MAC 头。如果在本地 ARP 映射表中查找出 IP 地址 192.168.1.2 所对应的 MAC 地址,则可以直接使用;如果没有,则需要发送 ARP 协议查询 MAC 地址,获得 MAC 地址后,由数据链路层构建一个数据帧,目的地址是 IP 层传过来的 MAC 地址,源地址则是本机的 MAC 地址;还要附加上一些控制信息,依据以太网的介质访问规则,将它们传送出去。

主机 B 收到这个数据帧后,先检查它的目的 MAC 地址,并和本机的 MAC 地址对比,如符合,则接收,否则就丢弃。
接收后检查该数据帧,将 IP 数据包从帧中提取出来,交给本机的 IP 层。同样,IP 层检查后,将有用的信息提取后交给 ICMP 协议。
主机 B 会构建一个 ICMP 回送响应消息 数据包,回送响应数据包的 类型 字段为 0,序号 为接收到的请求数据包中的序号,然后再发送出去给主机 A。

在规定的时候间内,源主机如果没有接到 ICMP 的应答包,则说明目标主机不可达;如果接收到了 ICMP 回送响应消息,则说明目标主机可达。
此时,源主机会检查,用当前时刻减去该数据包最初从源主机上发出的时刻,就是 ICMP 数据包的时间延迟。
针对上面发送的事情,总结成了如下图:

当然这只是最简单的,同一个局域网里面的情况。如果跨网段的话,还会涉及网关的转发、路由器的转发等等。
但是对于 ICMP 的头来讲,是没什么影响的。会影响的是根据目标 IP 地址,选择路由的下一跳,还有每经过一个路由器到达一个新的局域网,需要换 MAC 头里面的 MAC 地址。
说了这么多,可以看出 ping 这个程序是 使用了 ICMP 里面的 ECHO REQUEST(类型为 8 ) 和 ECHO REPLY (类型为 0)。
traceroute —— 差错报文类型的使用
有一款充分利用 ICMP 差错报文类型 的应用叫做 traceroute(在 UNIX、MacOS 中是这个命令,而在 Windows 中对等的命令叫做 tracert )。
1. traceroute 作用一
traceroute 的第一个作用就是 故意设置特殊的 TTL,来追踪去往目的地时沿途经过的路由器。
traceroute 的参数指向某个 目的 IP 地址:
traceroute 192.168.1.100
这个作用是如何工作的呢?
它的原理就是利用 IP 包的 生存期限 从 1 开始按照顺序递增的同时发送 UDP 包,强制接收 ICMP 超时消息 的一种方法。
比如,将 TTL 设置为 1,则遇到第一个路由器,就牺牲了,接着返回 ICMP 差错报文网络包,类型是 时间超时。
接下来将 TTL 设置为 2,第一个路由器过了,遇到第二个路由器也牺牲了,也同时返回了 ICMP 差错报文数据包,如此往复,直到到达目的主机。
这样的过程,traceroute 就可以拿到了所有的路由器 IP。
当然有的路由器根本就不会返回这个 ICMP,所以对于有的公网地址,是看不到中间经过的路由的。
发送方如何知道发出的 UDP 包是否到达了目的主机呢?
traceroute 在发送 UDP 包时,会填入一个 不可能的端口号 值作为 UDP 目标端口号(大于 3000 )。当目的主机,收到 UDP 包后,会返回 ICMP 差错报文消息,但这个差错报文消息的类型是「端口不可达」。
所以,当差错报文类型是端口不可达时,说明发送方发出的UDP包到达了目的主机。
2. traceroute作用二
traceroute还有一个作用是 故意设置不分片,从而确定路径的MTU。
这样做的目的为了 路径MTU发现。因为有的时候我们并不知道路由器的MTU大小,以太网的数据链路上的MTU通常是1500字节,但是非以太网的MTU值就不一样了,所以我们要知道MTU的大小,从而控制发送的包大小。

它的工作原理:
首先在发送端主机发送IP数据报时,将IP包首部的 分片禁止标志位设置为1。根据这个标志位,途中的路由器不会对大数据包进行分片,而是将包丢弃。
随后,通过一个 ICMP 的不可达消息将 数据链路上MTU的值 一起给发送主机,不可达消息的类型为「需要进行分片但设置了不分片位」。
发送主机端每次收到ICMP差错报文时就 减少 包的大小,以此来定位一个合适的MTU值,以便能到达目标主机。
巨人的肩膀
[1] 竹下隆史. 图解TCP/IP. 人民邮电出版社.
[2] 刘超. 趣谈网络协议. 极客时间.
读者问答
读者问:“有个问题就是 A 的 ICMP 到了 B 后,B 为啥会自动给 A 一个回执 0?这是操作系统的底层设计吗?”
答:是的。当主机 B 收到主机 A 发送的 ICMP 回送请求(类型为 8)时,操作系统协议栈会自动组装一个 ICMP 回送应答(类型为 0),并将其发送回主机 A。这是操作系统的底层网络协议栈实现的功能。

via:
-
断网了,还能ping通 127.0.0.1 吗? 小白 yes的练级攻略 2023-12-20 10:50 浙江
https://mp.weixin.qq.com/s/w1jJzU8yx109DMnLdMcpPw -
ping 的原理_ping ip 测试的结果不同的原因-优快云博客 小林coding 于 2020-03-25 22:43:00 发布
https://blog.youkuaiyun.com/qq_34827674/article/details/105106807
1030

被折叠的 条评论
为什么被折叠?



