什么 是127.0.0.1
5.3 断网了,还能 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,那么可以省略不写。

在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 协议进行消息的传输。

所以,大家在这里完全可以简单的理解为 ping 某个IP 就是往某个IP 地址 发个消息。
TCP 发数据和ping 的区别
一般情况下,我们会使 用 TCP 进行网络数据传输,那么我们可以看下它和 ping 的区别。
PS
:下图中有一处画错了,右边是 tcp
数据,而不是 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 外网的时候是几乎是一样的。到了网络层,系统
会根据目的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 =804 9<UP,LOOPBACK,RUNNING,MULTICAST > mtu 16384inet 127.0 .0.1 netmask 0xff000000
.. .en0: flags =886 3<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1500inet 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 (0.0.0.0): 56 data bytesping: 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 和本机 地址 都可以访问到服务。
