網通不通,你 ping 一下就知道了。
可能看到標題,你就知道答案了,但是你了解背后的原因嗎?
那如果把 127.0.0.1 換成 0.0.0.0 或 localhost 會怎么樣呢?你知道這幾個IP有什么區別嗎?
話不多說,我們直接開車。
拔掉網線,斷網。
然后在控制臺輸入ping 127.0.0.1。
$ping127.0.0.1 PING127.0.0.1(127.0.0.1):56databytes 64bytesfrom127.0.0.1:icmp_seq=0ttl=64time=0.080ms 64bytesfrom127.0.0.1:icmp_seq=1ttl=64time=0.093ms 64bytesfrom127.0.0.1:icmp_seq=2ttl=64time=0.074ms 64bytesfrom127.0.0.1:icmp_seq=3ttl=64time=0.079ms 64bytesfrom127.0.0.1:icmp_seq=4ttl=64time=0.079ms ^C ---127.0.0.1pingstatistics--- 5packetstransmitted,5packetsreceived,0.0%packetloss round-tripmin/avg/max/stddev=0.074/0.081/0.093/0.006ms
說明,拔了網線,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,是因為源碼里就是這么定義的,也沒什么道理。
/*Addresstoloopbackinsoftwaretolocalhost.*/ #defineINADDR_LOOPBACK0x7f000001/*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" (這是個內核線程),它在收到軟中斷后就會立馬去鏈表里把消息取出,然后順著數據鏈路層、網絡層等層層往上傳遞最后給到應用程序。
工具人ksoftirqd
ping 回環地址和通過TCP等各種協議發送數據到回環地址都是走這條路徑。整條路徑從發到收,都沒有經過"真網卡"。之所以127.0.0.1叫本地回環地址,可以理解為,消息發出到這個地址上的話,就不會出網絡,在本機打個轉就又回來了。所以斷網,依然能 ping 通 127.0.0.1。
ping回環地址和ping本機地址有什么區別
我們在mac里執行 ifconfig 。
$ifconfig lo0:flags=8049mtu16384 inet127.0.0.1netmask0xff000000 ... en0:flags=8863 mtu1500 inet192.168.31.6netmask0xffffff00broadcast192.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中表示的是無效的目標地址。
$ping0.0.0.0 PING0.0.0.0(0.0.0.0):56databytes ping:sendto:Noroutetohost ping:sendto:Noroutetohost
但它還是很有用處的,回想下,我們啟動服務器的時候,一般會 listen 一個 IP 和端口,等待客戶端的連接。
如果此時 listen 的是本機的 0.0.0.0 , 那么它表示本機上的所有IPV4地址。
/*Addresstoacceptanyincomingmessages.*/ #defineINADDR_ANY((unsignedlongint)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和本機地址都可以訪問到服務。
審核編輯:劉清
-
IP協議
+關注
關注
3文章
85瀏覽量
22113 -
ICMP
+關注
關注
0文章
52瀏覽量
15292 -
TCP通信
+關注
關注
0文章
146瀏覽量
4556
原文標題:面試官:斷網了,還能 ping 通 127.0.0.1 嗎?
文章出處:【微信號:小林coding,微信公眾號:小林coding】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
在樹莓派上安裝和使用MySQL
ARM中斷的使能與除能如果把SETENA和CLRENA位都寫了1會怎么樣?
在Linux平臺下啟動和關閉MySQL服務
如果將float轉換成char類型為什么會提示報錯
用網線把STM32F407和電腦直連后ping不通是為什么呢?
如果給路由器天線換成5G信號塔天線會怎么樣?
如果把ad9643配置成測試模式, 一個時鐘周期內兩個通道通過LVDS接口輸出的數據是一樣的嗎?
如果把Xbox One X換成同等配置的PC 500美元做得到嗎?
IP地址的分類

評論