127.0.0.1 這是個 IPV4
地址。IPV4
地址有 32
位,一個字節有 8
位,共 4
個字節。其中127 開頭的都屬於回環地址,也是 IPV4
的特殊地址。而127.0.0.1
是眾多回環地址中的一個。之所以不是 127.0.0.2
,而是 127.0.0.1
,是因為源碼里就是這么定義的,也沒什么道理。
IPv4
的地址是 32
位的,2的32次方,大概是40+億
。地球光人口就76億。
所以就有了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 作為一個小軟件,它的功能比較簡單,就是嘗試發送一個小小的消息到目標機器上,判斷目的機器是否可達,其實也就是判斷目標機器網絡是否能連通。
TCP發數據和ping的區別
發送消息:
為了發送消息,那就得先知道往哪發。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 回環地址卻一切正常:
到了網絡層,系統會根據目的IP,在路由表中獲取對應的路由信息,而這其中就包含選擇哪個網卡把消息發出。
當發現目標IP是外網IP時,會從"真網卡"發出。
當發現目標IP是回環地址時,就會選擇本地網卡。
本地網卡,其實就是個"假網卡",它不像"真網卡"那樣有個ring buffer
什么的,"假網卡"會把數據推到一個叫 input_pkt_queue
的 鏈表 中。這個鏈表,其實是所有網卡共享的,上面掛着發給本機的各種消息。消息被發送到這個鏈表后,會再觸發一個軟中斷。
127.0.0.1 和 localhost 以及 0.0.0.0
localhost
就不叫 IP
,它是一個域名,就跟 "baidu.com"
,是一個形式的東西,只不過默認會把它解析為 127.0.0.1
,當然這可以在 /etc/hosts
文件下進行修改。
0.0.0.0
,執行 ping 0.0.0.0 ,是會失敗的,因為它在IPV4
中表示的是無效的目標地址。
啟動服務器的時候,一般會 listen
一個 IP 和端口,等待客戶端的連接。
如果此時 listen
的是本機的 0.0.0.0
, 那么它表示本機上的所有IPV4地址。