平常開發中,咱們常常會碰到查詢網絡是否暢通以及域名對應 IP 地址等小需求,這時候用的最多的應該就是 ping 命令了。 那你知道 ping 命令是怎麼工做的嗎?今天,咱們就來一塊兒認識下 ping 命令及其對應的 ICMP 協議。網絡
ICMP 全稱 Internet Control Message Protocol,指互聯網控制報文協議。3d
網絡自己是不可靠的,數據包在傳輸過程當中,可能會發生不少突發事件並致使數據傳輸失敗。而網絡層的 IP 協議是一個無鏈接的協議,它不會處理網絡層的故障,所以,咱們須要其它的協議,在數據包傳輸出現故障時,能將故障信息傳回來,這樣才能對應處理相關問題。cdn
就像在電視劇裏看到的古代戰爭同樣,打仗的時候須要經過斥候來傳遞戰局狀況,進而更好的控制戰局。而 ICMP 報文在網絡世界中就充當「斥候」這樣的角色。blog
ICMP 報文是封裝在 IP 包裏面的。由於傳輸指令的時候,確定須要源地址和目標地址。它自己格式很是簡單,以下圖:事件
ICMP 報文有不少的類型,不一樣的類型有不一樣的代碼,最經常使用的類型是主動請求,代碼爲 8,主動請求的應答,代碼爲 0。從大的方面看能夠分爲 查詢報文類型和差錯報文類型。路由
咱們常常在電視劇裏聽到這樣的話:來人,前方戰事如何?斥候回來沒?一有狀況,馬上通報。開發
相似這種主帥發起,主動查看敵情的狀況,就對應着 ICMP的查詢報文類型。例如,常見的 ping 命令就是查詢報文,是一種主動請求,而且得到主動應答的 ICMP 協議。所以,ping 命令發出的包也是符合 ICMP 協議格式的,只不過它在後面增長了本身的格式。域名
對 ping 的主動請求,進行網絡抓包,稱爲 ICMP ECHO REQUEST。同理,主動請求的回覆,稱爲ICMP ECHO REPLY。比起原生的 ICMP,這裏面多了兩個字段,一個是標識符,另外一個是序號。這不難理解,大帥派出去兩隊斥候,一隊是找誰要的,一隊是偵查戰況的,要有個標識才能區分。it
另外一方面,派出去的斥候,都要編個號。若是派出去 10 個,回來 10 個,就說明前方戰況不錯。若是派出去 10 個,回來 2 個,就說明狀況可能不妙。io
在選項數據中,ping 還會存放發送請求的時間值,來計算往返時間,說明路程的長短。
差錯報文主要是用來將發送的出錯報文相關信息返回到源設備,以供源設備肯定若是更好的重發失敗的數據包。
仍是拿咱們的「大帥」舉例。
當主帥正在大賬中看地圖,思考戰事時,外面的小兵忽然喊到:大帥,很差啦,張將軍遭遇埋伏,全軍覆沒了。
這種是異常狀況發起的,來報告發生了很差的事情,對應 ICMP 的差錯報文。
差錯報文有如下經常使用的類型:
第一種狀況終點不可達。小兵報告,大帥,送給張將軍的糧草沒有送到。
那大帥確定會問,爲啥沒有送到?這就對應 ICMP 中的如下代碼了。
具體的場景就像這樣:
第二種是源站抑制。也就是讓源站放慢發送速度(小兵:大帥,糧草送的太多了吃不完,你能夠慢點送)。
第三種是時間超時。也就是超過網絡包的生存時間仍是沒到目的地(大帥,送糧草的人都把糧食吃完了,還沒到地方,已經餓死了)。
第四種是路由重定向。也就是下次發給另外一個路由器(大帥,上次送糧草的人原本只要走大王村,一千米就到了,結果非要繞道張家界,多了五千米,下次記得走大王村)。
差錯報文的結構相對複雜一些。除了前面仍是 IP,ICMP 的前 8 個字節不變,後面則跟上出錯的那個 IP 包的 IP 頭和 IP 正文的前 8 個字節。
並且這類斥候特別盡責,不但字節返回來報信,還把一部分遺物帶回來。
接下來,咱們重點來看 ping 命令的發送和接收過程。
假定主機 A 的 IP 地址是 192.168.1.1,主機 B 的 IP 地址是 192.168.1.2,它們都在同一個子網。那麼,當在主機 A 上運行「ping 192.168.1.2」 後,會發生什麼呢?
主機 B 收到數據幀後,會進行以下步驟:
在規定的時間內,源主機若是沒有接到 ICMP 的應答包,則說明目標主機不可達。
若是接收到了應打包,則說明目標主機可達。此時,源主機會檢測時間延遲。就是用當前時刻減該數據包從源主機發出去的時刻。
固然,這只是最簡單的,同個局域網的狀況。若是跨網段的話,還會涉及網關的轉發、路由器的轉發等。
能夠看出,ping 命令是使用了 ICMP 裏面的 ECHO REQUEST 和 ECHO REPLY 類型。
那其它類型呢?是否是隻有真正遇到錯誤的時候,才能收到?答案是否認的。有一個 Traceroute 命令,它會使用 ICMP 的規則,故意製造一些可以產生錯誤的場景。
Traceroute 命令有兩個比較經常使用的功能。
第一個功能:
經過設置特殊的 TTL,追蹤去往目的地時通過的路由器
Traceroute 的參數執行某個目的 IP 地址,會發送一個 UDP 的數據包。
將 TTL 設置成 1 時,表示這個數據包的 MP 爲 1,碰到第一個「攔路虎」(一般是路由器或一個其它類型的關卡)就會陣亡了,而後就會返回一個 ICMP 包,這個包就是 網絡差錯包,類型是時間超時。
經過差錯包,咱們就能獲得數據包到第一個關卡時花費的時間及其每一個關卡的 IP 地址(有的主機不會響應 ICMP,因此會出現請求時全是 * 的狀況)。
那怎麼知道 UDP 有沒有到達目的主機呢?Traceroute 程序會發送一份 UDP 數據包給目的主機,但它會選擇一個不可能的值做爲 UDP 端口號(大於30000)。當該數據報到達目的主機時,因爲找不到對應端口號,因此會返回一個「端口不可達」的錯誤報文。這樣,咱們就知道 UDP 是否到達主機了。
第二個功能:
設置數據包不分片,肯定路徑的 MTU
發送分組,並設置「不分片」標誌。發送的第一個分組的長度正好與出口的 MTU 相等。若是中間遇到窄的關卡就會被卡主,返回 ICMP 網絡差錯包,類型是「須要進行分片但設置了不分片」。就這樣,每次收到ICMP「不能分片」差錯時就減少分組的長度,從而肯定整個路徑中的 MTU。
參考: