作者:王奎,個(gè)人公號:不止思考
我們在遇到網(wǎng)絡(luò )不通的情況,大家都知道去 ping 一下,看一下網(wǎng)絡(luò )狀況。
那你知道「ping」命令后背的邏輯是什么嗎?知道它是如何實(shí)現的嗎?
簡(jiǎn)單來(lái)說(shuō),「ping」是用來(lái)探測本機與網(wǎng)絡(luò )中另一主機之間是否可達的命令,如果兩臺主機之間ping不通,則表明這兩臺主機不能建立起連接。ping是定位網(wǎng)絡(luò )通不通的一個(gè)重要手段。
ping 命令是基于 ICMP 協(xié)議來(lái)工作的,「 ICMP 」全稱(chēng)為 Internet 控制報文協(xié)議( Internet Control Message Protocol)。ping 命令會(huì )發(fā)送一份ICMP回顯請求報文給目標主機,并等待目標主機返回ICMP回顯應答。因為ICMP協(xié)議會(huì )要求目標主機在收到消息之后,必須返回ICMP應答消息給源主機,如果源主機在一定時(shí)間內收到了目標主機的應答,則表明兩臺主機之間網(wǎng)絡(luò )是可達的。
舉一個(gè)例子來(lái)描述「ping」命令的工作過(guò)程:
假設有兩個(gè)主機,主機A(192.168.0.1)和主機B(192.168.0.2),現在我們要監測主機A和主機B之間網(wǎng)絡(luò )是否可達,那么我們在主機A上輸入命令:ping 192.168.0.2
此時(shí),ping命令會(huì )在主機A上構建一個(gè) ICMP的請求數據包(數據包里的內容后面再詳述),然后 ICMP協(xié)議會(huì )將這個(gè)數據包以及目標IP(192.168.0.2)等信息一同交給IP層協(xié)議。
IP層協(xié)議得到這些信息后,將源地址(即本機IP)、目標地址(即目標IP:192.168.0.2)、再加上一些其它的控制信息,構建成一個(gè)IP數據包。
IP數據包構建完成后,還不夠,還需要加上MAC地址,因此,還需要通過(guò)ARP映射表找出目標IP所對應的MAC地址。當拿到了目標主機的MAC地址和本機MAC后,一并交給數據鏈路層,組裝成一個(gè)數據幀,依據以太網(wǎng)的介質(zhì)訪(fǎng)問(wèn)規則,將它們傳送出出去。
當主機B收到這個(gè)數據幀之后,會(huì )首先檢查它的目標MAC地址是不是本機,如果是就接收下來(lái)處理,接收之后會(huì )檢查這個(gè)數據幀,將數據幀中的IP數據包取出來(lái),交給本機的IP層協(xié)議,然后IP層協(xié)議檢查完之后,再將ICMP數據包取出來(lái)交給ICMP協(xié)議處理,當這一步也處理完成之后,就會(huì )構建一個(gè)ICMP應答數據包,回發(fā)給主機A
在一定的時(shí)間內,如果主機A收到了應答包,則說(shuō)明它與主機B之間網(wǎng)絡(luò )可達,如果沒(méi)有收到,則說(shuō)明網(wǎng)絡(luò )不可達。除了監測是否可達以外,還可以利用應答時(shí)間和發(fā)起時(shí)間之間的差值,計算出數據包的延遲耗時(shí)。
通過(guò)ping的流程可以發(fā)現,ICMP協(xié)議是這個(gè)過(guò)程的基礎,是非常重要的,因此下面就把ICMP協(xié)議再詳細解釋一下。
我們知道,ping命令是基于ICMP協(xié)議來(lái)實(shí)現的。那么我們再來(lái)看下圖,就明白了ICMP協(xié)議又是通過(guò)IP協(xié)議來(lái)發(fā)送的,即ICMP報文是封裝在IP包中。
IP協(xié)議是一種無(wú)連接的,不可靠的數據包協(xié)議,它并不能保證數據一定被送達,那么我們要保證數據送到就需要通過(guò)其它模塊來(lái)協(xié)助實(shí)現,這里就引入的是ICMP協(xié)議。
當傳送的IP數據包發(fā)送異常的時(shí)候,ICMP就會(huì )將異常信息封裝在包內,然后回傳給源主機。
將上圖再細拆一下可見(jiàn):
繼續將ICMP協(xié)議模塊細拆:
由圖可知,ICMP數據包由8bit的類(lèi)型字段和8bit的代碼字段以及16bit的校驗字段再加上選項數據組成。
ICMP協(xié)議大致可分為兩類(lèi):
查詢(xún)報文類(lèi)型
差錯報文類(lèi)型
查詢(xún)報文類(lèi)型:
查詢(xún)報文主要應用于:ping查詢(xún)、子網(wǎng)掩碼查詢(xún)、時(shí)間戳查詢(xún)等等。
上面講到的ping命令的流程其實(shí)就對應ICMP協(xié)議查詢(xún)報文類(lèi)型的一種使用。在主機A構建ICMP請求數據包的時(shí)候,其ICMP的類(lèi)型字段中使用的是 8 (回送請求),當主機B構建ICMP應答包的時(shí)候,其ICMP類(lèi)型字段就使用的是 0 (回送應答),更多類(lèi)型值參考上表。
對 查詢(xún)報文類(lèi)型 的理解可參考一下文章最開(kāi)始講的ping流程,這里就不做贅述。
差錯報文類(lèi)型:
差錯報文主要產(chǎn)生于當數據傳送發(fā)送錯誤的時(shí)候。
它包括:目標不可達(網(wǎng)絡(luò )不可達、主機不可達、協(xié)議不可達、端口不可達、禁止分片等)、超時(shí)、參數問(wèn)題、重定向(網(wǎng)絡(luò )重定向、主機重定向等)等等。
差錯報文通常包含了引起錯誤的IP數據包的第一個(gè)分片的IP首部,加上該分片數據部分的前8個(gè)字節。
當傳送IP數據包發(fā)生錯誤的時(shí)候(例如 主機不可達),ICMP協(xié)議就會(huì )把錯誤信息封包,然后傳送回源主機,那么源主機就知道該怎么處理了。
那是不是只有遇到錯誤的時(shí)候才能使用 差錯報文類(lèi)型 呢?也不一定。
Traceroute 就是一個(gè)例外,Traceroute是用來(lái)偵測源主機到目標主機之間所經(jīng)過(guò)路由情況的常用工具。Traceroute 的原理就是利用ICMP的規則,制造一些錯誤的事件出來(lái),然后根據錯誤的事件來(lái)評估網(wǎng)絡(luò )路由情況。
具體做法就是:
Traceroute會(huì )設置特殊的TTL值,來(lái)追蹤源主機和目標主機之間的路由數。首先它給目標主機發(fā)送一個(gè) TTL=1 的UDP數據包,那么這個(gè)數據包一旦在路上遇到一個(gè)路由器,TTL就變成了0(TTL規則是每經(jīng)過(guò)一個(gè)路由器都會(huì )減1),因為T(mén)TL=0了,所以路由器就會(huì )把這個(gè)數據包丟掉,然后產(chǎn)生一個(gè)錯誤類(lèi)型(超時(shí))的ICMP數據包回發(fā)給源主機,也就是差錯包。這個(gè)時(shí)候源主機就拿到了第一個(gè)路由節點(diǎn)的IP和相關(guān)信息了。
接著(zhù),源主機再給目標主機發(fā)一個(gè) TTL=2 的UDP數據包,依舊上述流程走一遍,就知道第二個(gè)路由節點(diǎn)的IP和耗時(shí)情況等信息了。
如此反復進(jìn)行,Traceroute就可以拿到從主機A到主機B之間所有路由器的信息了。
但是有個(gè)問(wèn)題是,如果數據包到達了目標主機的話(huà),即使目標主機接收到TTL值為1的IP數據包,它也是不會(huì )丟棄該數據包的,也不會(huì )產(chǎn)生一份超時(shí)的ICMP回發(fā)數據包的,因為數據包已經(jīng)達到了目的地嘛。那我們應該怎么認定數據包是否達到了目標主機呢?
Traceroute的方法是在源主機發(fā)送UDP數據包給目標主機的時(shí)候,會(huì )設置一個(gè)不可能達到的目標端口號(例如大于30000的端口號),那么當這個(gè)數據包真的到達目標主機的時(shí)候,目標主機發(fā)現沒(méi)有對應的端口號,因此會(huì )產(chǎn)生一份“端口不可達”的錯誤ICMP報文返回給源主機。
可見(jiàn)Traceroute的原理確實(shí)很取巧,很有趣。
以上,就是對ping的基本原理以及ICMP協(xié)議的基本講解了,歡迎大家一起交流。
【關(guān)于作者】
王奎:不止思考的技術(shù)人,一名駐扎在武漢互聯(lián)網(wǎng)的程序員老兵,我有一個(gè)公眾號 bzsikao 平時(shí)寫(xiě)一些工作的心得和技術(shù)文章。
【關(guān)于投稿】
如果大家有原創(chuàng )好文投稿,請直接給公號發(fā)送留言。
① 留言格式:
【投稿】 《 文章標題》 文章鏈接
② 示例:
【投稿】《不要自稱(chēng)是程序員,我十多年的 IT 職場(chǎng)總結》:
http://blog.jobbole.com/94148/
③ 最后請附上您的個(gè)人簡(jiǎn)介哈~
關(guān)注「程序員的那些事」,不錯過(guò)圈內事
聯(lián)系客服