我們在遇到網絡不通的情況,大家都知道去 ping 一下,看一下網絡狀況。
那你知道「ping」指令後背的邏輯是什麼嗎?知道它是如何實作的嗎?
一、「ping」指令的作用和原理?
簡單來說,「ping」是用來探測本機與網絡中另一主機之間是否可達的指令,如果兩台主機之間ping不通,則表明這兩台主機不能建立起連接配接。ping是定位網絡通不通的一個重要手段。
ping 指令是基于 ICMP 協定來工作的,「 ICMP 」全稱為 Internet 控制封包協定( Internet Control Message Protocol)。ping 指令會發送一份ICMP回應要求封包給目标主機,并等待目标主機傳回ICMP回應答覆。因為ICMP協定會要求目标主機在收到消息之後,必須傳回ICMP應答消息給源主機,如果源主機在一定時間内收到了目标主機的應答,則表明兩台主機之間網絡是可達的。
舉一個例子來描述「ping」指令的工作過程:
- 假設有兩個主機,主機A(192.168.0.1)和主機B(192.168.0.2),現在我們要監測主機A和主機B之間網絡是否可達,那麼我們在主機A上輸入指令:ping 192.168.0.2
- 此時,ping指令會在主機A上建構一個 ICMP的請求資料包(資料包裡的内容後面再詳述),然後 ICMP協定會将這個資料包以及目标IP(192.168.0.2)等資訊一同交給IP層協定。
- IP層協定得到這些資訊後,将源位址(即本機IP)、目标位址(即目标IP:192.168.0.2)、再加上一些其它的控制資訊,建構成一個IP資料包。
- IP資料包建構完成後,還不夠,還需要加上MAC位址,是以,還需要通過ARP映射表找出目标IP所對應的MAC位址。當拿到了目标主機的MAC位址和本機MAC後,一并交給資料鍊路層,組裝成一個資料幀,依據以太網的媒體通路規則,将它們傳送出出去。
- 當主機B收到這個資料幀之後,會首先檢查它的目标MAC位址是不是本機,如果是就接收下來處理,接收之後會檢查這個資料幀,将資料幀中的IP資料包取出來,交給本機的IP層協定,然後IP層協定檢查完之後,再将ICMP資料包取出來交給ICMP協定處理,當這一步也處理完成之後,就會建構一個ICMP應答資料包,回發給主機A
- 在一定的時間内,如果主機A收到了應答包,則說明它與主機B之間網絡可達,如果沒有收到,則說明網絡不可達。除了監測是否可達以外,還可以利用應答時間和發起時間之間的內插補點,計算出資料包的延遲耗時。
通過ping的流程可以發現,ICMP協定是這個過程的基礎,是非常重要的,是以下面就把ICMP協定再詳細解釋一下。
二、什麼是「 ICMP 」?
我們知道,ping指令是基于ICMP協定來實作的。那麼我們再來看下圖,就明白了ICMP協定又是通過IP協定來發送的,即ICMP封包是封裝在IP包中。

IP協定是一種無連接配接的,不可靠的資料包協定,它并不能保證資料一定被送達,那麼我們要保證資料送到就需要通過其它子產品來協助實作,這裡就引入的是ICMP協定。
當傳送的IP資料包發送異常的時候,ICMP就會将異常資訊封裝在包内,然後回傳給源主機。
将上圖再細拆一下可見:
繼續将ICMP協定子產品細拆:
由圖可知,ICMP資料包由8bit的類型字段和8bit的代碼字段以及16bit的校驗字段再加上選項資料組成。
ICMP協定大緻可分為兩類:
- 查詢封包類型
- 差錯封包類型
- 查詢封包類型:
查詢封包主要應用于:ping查詢、子網路遮罩查詢、時間戳查詢等等。
上面講到的ping指令的流程其實就對應ICMP協定查詢封包類型的一種使用。在主機A建構ICMP請求資料包的時候,其ICMP的類型字段中使用的是 8 (回送請求),當主機B建構ICMP應答包的時候,其ICMP類型字段就使用的是 0 (回送應答),更多類型值參考上表。
對 查詢封包類型 的了解可參考一下文章最開始講的ping流程,這裡就不做贅述。
- 差錯封包類型:
差錯封包主要産生于當資料傳送發送錯誤的時候。
它包括:目标不可達(網絡不可達、主機不可達、協定不可達、端口不可達、禁止分片等)、逾時、參數問題、重定向(網絡重定向、主機重定向等)等等。
差錯封包通常包含了引起錯誤的IP資料包的第一個分片的IP首部,加上該分片資料部分的前8個位元組。
當傳送IP資料包發生錯誤的時候(例如 主機不可達),ICMP協定就會把錯誤資訊封包,然後傳送回源主機,那麼源主機就知道該怎麼處理了。
那是不是隻有遇到錯誤的時候才能使用 差錯封包類型 呢?也不一定。
Traceroute 就是一個例外,Traceroute是用來偵測源主機到目标主機之間所經過路由情況的常用工具。Traceroute 的原理就是利用ICMP的規則,制造一些錯誤的事件出來,然後根據錯誤的事件來評估網絡路由情況。
具體做法就是:
Traceroute會設定特殊的TTL值,來追蹤源主機和目标主機之間的路由數。首先它給目标主機發送一個 TTL=1 的UDP資料包,那麼這個資料包一旦在路上遇到一個路由器,TTL就變成了0(TTL規則是每經過一個路由器都會減1),因為TTL=0了,是以路由器就會把這個資料包丢掉,然後産生一個錯誤類型(逾時)的ICMP資料包回發給源主機,也就是差錯包。這個時候源主機就拿到了第一個路由節點的IP和相關資訊了。
接着,源主機再給目标主機發一個 TTL=2 的UDP資料包,依舊上述流程走一遍,就知道第二個路由節點的IP和耗時情況等資訊了。
如此反複進行,Traceroute就可以拿到從主機A到主機B之間所有路由器的資訊了。
但是有個問題是,如果資料包到達了目标主機的話,即使目标主機接收到TTL值為1的IP資料包,它也是不會丢棄該資料包的,也不會産生一份逾時的ICMP回發資料包的,因為資料包已經達到了目的地嘛。那我們應該怎麼認定資料包是否達到了目标主機呢?
Traceroute的方法是在源主機發送UDP資料包給目标主機的時候,會設定一個不可能達到的目标端口号(例如大于30000的端口号),那麼當這個資料包真的到達目标主機的時候,目标主機發現沒有對應的端口号,是以會産生一份“端口不可達”的錯誤ICMP封包傳回給源主機。
可見Traceroute的原理确實很取巧,很有趣。
以上,就是對ping的基本原理以及ICMP協定的基本講解了,歡迎大家一起交流。
本文原創釋出于微信公衆号「 不止思考 」,歡迎關注,交流Java、Web、架構、大資料、職業發展、技術管理。![]()
當你「ping 一下」的時候,你知道它背後的邏輯嗎?
作者微信公衆号「 bzsikao 」,歡迎關注,交流更多的 網際網路認知、工作管理、大資料、Web、區塊鍊技術。