断网了,还能 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,顺着网卡就发出去了。<