你女神愛不愛你,你問她,她可能不會告訴你。
?
但網通不通,你 ping 一下就知道了。
可能看到標題,你就知道答案了,但是你了解背后的原因嗎?
那如果把 127.0.0.1 換成 0.0.0.0 或 會怎么樣呢?你知道這幾個IP有什么區別嗎?
以前面試的時候就遇到過這個問題,大家看個動圖了解下面試官和我當時的場景,求當時我的心里陰影面積。
話不多說,我們直接開車。
拔掉網線,斷網。
斷開wifi
網線一拔,恩怨去了
然后在控制臺輸入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個冒號:ping怎么測試端口有沒有問題, 是因為一個 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里萬物皆文件,那你要發消息的目的地,也是個文件,這里就引出了 的概念。
要使用 , 那么首先需要創建它。
在 TCP 傳輸中創建的方式是 (, , 0);,其中 表示將使用 IPV4 里 host:port 的方式去解析待會你輸入的網絡地址。 是指使用面向字節流的 TCP 協議,工作在傳輸層。
創建好了 之后,就可以愉快的把要傳輸的數據寫到這個文件里。調用 的接口的過程中進程會從用戶態進入到內核態ping怎么測試端口有沒有問題,最后會調用到 方法。
然后進入傳輸層,帶上TCP頭。網絡層帶上IP頭,數據鏈路層帶上 MAC頭等一系列操作后。進入網卡的發送隊列 ring ,順著網卡就發出去了。
回到 ping , 整個過程也基本跟 TCP 發數據類似,差異的地方主要在于,創建 的時候用的是 (,,), 是原始套接字 ,工作在網絡層, 所以構建ICMP(網絡層協議)的數據,是再合適不過了。ping 在進入內核態后最后也是調用的 方法,進入到網絡層后加上ICMP和IP頭后,數據鏈路層加上MAC頭,也是順著網卡發出。因此 本質上ping 跟 普通應用發消息 在程序流程上沒太大差別。
這也解釋了為什么當你發現懷疑網絡有問題的時候,別人第一時間是問你能ping通嗎?因為可以簡單理解為ping就是自己組了個數據包,讓系統按著其他軟件發送數據的路徑往外發一遍,能通的話說明其他軟件發的數據也能通。
為什么斷網了還能 ping 通 127.0.0.1
前面提到,有網的情況下,ping 最后是通過網卡將數據發送出去的。
那么斷網的情況下,網卡已經不工作了,ping 回環地址卻一切正常,我們可以看下這種情況下的工作原理。
ping回環地址
從應用層到傳輸層再到網絡層。這段路徑跟ping外網的時候是幾乎是一樣的。到了網絡層,系統會根據目的IP,在路由表中獲取對應的路由信息,而這其中就包含選擇哪個網卡把消息發出。
當發現目標IP是外網IP時,會從"真網卡"發出。
當發現目標IP是回環地址時,就會選擇本地網卡。
本地網卡,其實就是個"假網卡",它不像"真網卡"那樣有個ring 什么的,"假網卡"會把數據推到一個叫 的 鏈表 中。這個鏈表,其實是所有網卡共享的,上面掛著發給本機的各種消息。消息被發送到這個鏈表后,會再觸發一個軟中斷。
專門處理軟中斷的工具人"" (這是個內核線程),它在收到軟中斷后就會立馬去鏈表里把消息取出,然后順著數據鏈路層、網絡層等層層往上傳遞最后給到應用程序。
工具人
ping 回環地址和通過TCP等各種協議發送數據到回環地址都是走這條路徑。整條路徑從發到收,都沒有經過"真網卡"。之所以127.0.0.1叫本地回環地址,可以理解為,消息發出到這個地址上的話,就不會出網絡,在本機打個轉就又回來了。所以斷網,依然能 ping 通 127.0.0.1。
ping回環地址和ping本機地址有什么區別
我們在mac里執行 。
$?ifconfig
lo0:?flags=8049?mtu?16384

????inet?127.0.0.1?netmask?0xff000000
????...
en0:?flags=8863?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 和 以及 0.0.0.0 有區別嗎
回到文章開頭動圖里的提問,算是面試八股文里的老常客了。
以前第一次用 nginx 的時候,發現用這幾個 IP,都能正常訪問到 nginx 的歡迎網頁。一度認為這幾個 IP 都是一樣的。
訪問127.0.0.1:80
訪問:80
訪問0.0.0.0:80
訪問本機的IP地址
但本質上還是有些區別的。
首先 就不叫 IP,它是一個域名,就跟 "",是一個形式的東西,只不過默認會把它解析為 127.0.0.1 ,當然這可以在 /etc/hosts 文件下進行修改。
所以默認情況下,使用 跟使用 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
但它還是很有用處的,回想下,我們啟動服務器的時候,一般會 一個 IP 和端口,等待客戶端的連接。
如果此時 的是本機的 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 ,那么用上面兩個地址,都能訪問到這個服務器。
當然, 客戶端 時,不能使用 0.0.0.0 。必須指明要連接哪個服務器IP。
總結