主頁 > 後端開發 > 所謂 ICMP,不過將軍與士卒而已

所謂 ICMP,不過將軍與士卒而已

2021-04-29 08:06:13 後端開發

什么是 ICMP 協議

關于這點我們在 IP 協議那篇文章中提過一嘴,IP 協議作為一種提供不可靠資料交付的網路層協議,在傳輸的程序中,其 IP 資料報可能會發生丟失、重復、延遲和亂序等各種情況, 但是 IP 協議對這些糟糕的情況并不擁有有效的檢測和彌補措施,當然更不會將這些結果通知收發雙方,

為此,鑒于上述原因,我們在構建 IP 網路時,就需要特別注意兩點:

  • 確認網路是否能夠正常作業
  • 即使診斷出現例外時的原因所在

于是,網際控制報文協議(Internet Control Message Protocol,ICMP)出現了,

形象來說,IP 協議就好像一個將軍,而 ICMP 協議就是他手下的情報員,將軍運籌帷幄于千里之外,而在前線浴血奮戰的士卒們傷亡當然也在所難免,

那無法親臨前線的將軍最起碼要知道兩件事情:第一點,我的士卒們是不是按照我指引的方向在前進著,別一陣猛沖發現沖錯了地方;第二點,我的士卒們傷亡多少,被什么所傷,了解了己方傷亡的原因才好做下一步的戰略部署,總不能死了個不明白,不必多說,這就是情報員 ICMP 該做的事情了,

當然了,上述只是打個比方,可能不是很嚴謹,各位知道什么意思就行,不必過于吹毛求疵,

這里我們再用學術點的語言來總結下,ICMP 的主要功能有如下兩點:

1)確認 IP 資料報是否成功送達目標地址

2)如果某個 IP 資料報因為某種原因未能正常到達目的地,則由 ICMP 負責通知具體的原因

ICMP 報文初探

具體的出錯原因是 ICMP 協議負責通知的,這個通知的學名就是 ICMP 報文,那么 ICMP 報文是由發送方發送方發出的還是由接收方發出的呢?

都不是,

ICMP 報文是由路由器發出來的

舉個例子:主機 A 在不知情的情況下向主機 B 發送了資料包,而主機 B 正在呼呼大睡,主機 A 和主機 B 不在同一個區域網內,假設它倆之間會經過兩個路由器,看下圖:

眾所周知,除了 IP 地址我們還需要 MAC 地址才能確保資料包精準的找到傳送方向,因此,路由器 2 為了知道主機 B 的 MAC 地址,它會廣播一個 ARP 請求報文,希望獲取到主機 B 的 MAC 地址,而主機 B 都關機了自然也就無法應答這個請求報文了,

為此,路由器 2 會一遍又一遍的重新發送著 ARP 請求報文,在多次無果后,路由器 2 就會回傳一個 ICMP Destination Unreachable 的包給主機 A(關于 ICMP 報文型別下文會講),通知主機 A,非常遺憾,您發往主機 B 的包未能成功抵達,

那么,ICMP 報文具體是怎么傳輸給主機 A 的呢

這個很簡單,TCP/UDP 報文是怎么傳輸的,ICMP 報文就怎么傳輸,

也就是說,真正的資料首先會被加上 ICMP 首部,封裝成 ICMP 報文,然后被 IP 協議封裝成 IP 資料報進行明文傳輸,由 IP 協議指定源 IP 地址和目的地址,主機 A 收到資料后會一層一層解封裝,從而獲得真正的資料得知發生例外的原因,遂大怒一聲:蠢貨主機 B,

ICMP 報文格式

至此,各位已經知道了,ICMP 報文是被封裝在 IP 資料報里面的,我們來看看下圖:

額,這里好像沒啥好說的,上圖畫的很 Nice ,是我之前考研的時候看 B 站上的王道視頻截下來的,各位看明白上圖,了解 ICMP 報頭有哪些東西,知道型別代碼這兩個欄位很重要就好了,尤其是型別這個,接下來我們先重點講它,

ICMP 報文型別

上文提到了 ICMP Destination Unreachable,也就是目標不可達的 ICMP 報文,

ICMP 報文型別大體上可以分為兩種,差錯報文和詢問報文,解釋一下:

所謂查詢報文就是,用于主機進行診斷的查詢訊息

這么學術性的文字可能不是很好理解,這樣,咱形象來說,查詢報文其實和通信例外沒啥關系,查詢報文就好比將軍率領著千軍萬馬來到了一片寂靜的峽谷,正是一個容易被埋伏的地方,將軍不敢貿然前進,于是派遣幾個情報員前去探明敵情,一有動靜立馬回報,

常見的 ICMP 查詢報文型別有以下幾種:

  • 回送應答(Echo Reply),對應 ICMP 報文首部型別欄位的值:0
  • 回送請求(Echo Request),對應 ICMP 報文首部型別欄位的值:8

而差錯報文就是,用于通知主機出錯的原因,顯然,ICMP 差錯報告報文是伴隨著出錯資料產生的,一旦 IP 協議發現某個 IP 資料報出錯了,首先就會毅然地丟棄出錯的這個 IP 資料報,然后發送 ICMP 差錯報文

常見的 ICMP 差錯報文型別有以下幾種:

  • 目標不可達(Destination Unreachable),對應 ICMP 報文首部型別欄位的值:3
  • 原點抑制(Source Quench),對應 ICMP 報文首部型別欄位的值:4
  • 重定向或改變路由(Redirect),對應 ICMP 報文首部型別欄位的值:5
  • 超時(Time Exceeded),對應 ICMP 報文首部型別欄位的值:11

下面詳細解釋一下這幾個常見的 ICMP 報文型別,

ICMP 回送訊息(型別 0、8)

用于進行通信的主機或路由器之間,判斷所發送的資料包是否已經成功到達對端的一種訊息,

可以向對端主機發送 ICMP 回送請求的訊息(Echo Request,型別 8),也可以接收對端主機發回來的 ICMP 回送應答訊息(Echo Reply,型別 0)

我們常用的 ping 命令就是基于 ICMP 回送訊息實作的,

ping 這個單詞源自聲納定位,而這個命令的作用也確實如此,它發送型別為 0 的 ICMP Echo Request 訊息,收到請求的主機則用型別為 8 的 ICMP Echo Reply 訊息進行回應,ping 就會計算發送 Requenst 和接收到 Reply 的訊息間隔時間,并計算有多少個包被送達,丟失了多少個包等,用戶就可以據此判斷網路大致的情況,

如下圖我們來 ping 一下 Github:

ping 也并不是啥事也沒做,它在 ICMP 報文格式中又添加了兩個欄位:識別符號和序號,這倆其實很好理解:

1)識別符號用來區分是哪個應用程式發 ICMP 包,

形象來說,將軍派出了兩個情報員,一個用來是了解戰況的,一個是用來搬救兵的,那總得有個標識區分這倆情報員吧,識別符號就是干這事的,最容易想到的能作為識別符號的東西,想來也不用我多嘴吧,就是行程的 PID,

2)序號用來確認網路包是否有丟失,

形象來說,將軍派出了 10 個情報員,給每個情報員都編個號,這樣,如果派出去 10 個,回來 10 個,就說明前方戰況不錯;如果派出去 10 個,一個也沒回來或者就回來 1 個,說明情況不妙啊,

ICMP 目標不可達訊息(型別 3)

路由器無法將 IP 資料報發送給目標地址時,會給發送端主機回傳一個目標不可達(Destination Unreachable Message)的 ICMP 訊息,

那目標不可達有多種可能的原因,比如說網路問題、目標主機問題等等,所以這個目標不可達訊息還需要指明不可達的具體原因,這個具體原因就記錄在 ICMP 報頭的代碼欄位,

那么這里我們仍然以行軍打戰的例子來看看常見的目標不可達型別的代碼有哪些:

1)前方戰事吃緊,將軍(主機 A)派了一隊士兵回京城找皇上(主機 B)搬救兵,中途情報員快馬加鞭趕到匯報:將軍,我們在途中迷失了方向,找不到京城在哪,這就是網路不可達,其代碼為 0

2)假設士兵們成功回到京城,但是皇上出城了,不在京城,朝廷百官也不敢私自同意出兵救援,這就是主機不可達,到了地方卻沒找到人,其代碼為 1

3)假設士兵成功找到了京城,但是由于將士們常年在外征戰,守城的年輕護衛們已經不認識這些威名赫赫的將士們了,所以需要進城口令證明身份,但是久經沙場的將士們一時半會想不起來這些東西,遂無法進城,這就是協議不可達,其代碼為 2

4)假設士兵們成功進了城,也成功面見了圣上,但是皇上卻說密偵司告訴他的情報和你們說的不一樣,你們說你們需要的是救兵,而我得到的訊息是你們只需要糧草,這就是埠不可達,其代碼為 3

5)假設士兵們成功求得了救兵,并且獲得了火器十余箱,但是中途山路狹窄,裝火器的馬車太大過不去,為此需要換小一點的馬車,每個馬車裝一點,但是由于火器技術尚不成熟,考慮安全問題,將軍早就嚴令禁止把火器分裝,于是乎,浩浩蕩蕩的援兵阻塞在了狹窄的山路,這就是需要進行分片但設定了不分片位,其代碼為 4

ICMP 重定向訊息(型別 5)

說到這個,我們先要明白 IP 協議或者網路層的職責是什么,就是選擇合適的網間路由和交換結點, 確保資料的及時傳送,

為此,我們總是傾向于基于最短最優的路徑進行傳輸,

那么如果路由器發現發送端主機使用了某個不是最優的路徑發送資料,他就會回傳一個 ICMP 重定向訊息(ICMP Redirect Message)給這個主機,并且,在這個訊息中包含了最優的路由資訊和源資料,

寫上癮了哈哈,舉個例子:將軍得知 ICMP 的情報后震怒,派出去搬救兵的領隊竟然帶著十萬救兵在繞彎子,亂臣賊子,將軍趕緊下令誅殺這個領隊并立即走最近的路趕回來,

ICMP 超時訊息(型別 11)

IP 包中有一個欄位叫做 TTLTime To Live,生存周期),它的值隨著每經過一次路由器就會減 1,直到減到 0 時該 IP 包會被丟棄

此時,IP 路由器將會發送一個 ICMP 超時訊息(ICMP Time Exceeded Message)給發送端主機,并通知該包已被丟棄,

形象來說,就是將軍派出去的搬救兵的那隊人馬苦于找不到京城的方向,路途開始帶上的只夠三天的糧草斷盡,全隊飲恨而死,

設定 IP 包生存周期的主要目的,是為了在路由控制遇到問題發生回圈狀況時,避免 IP 包無休止地在網路上被轉發,

ICMP 的應用

其中一個應用 ping 命令我們已經說過了,它是基于 ICMP 查詢報文的,

還有一個命令,是基于 ICMP 差錯報文的,在 Linux 下這條命令是 traceroute,在 Windows 是 tracert

大家可能會覺得 ICMP 差錯報文是只有在通信例外的時候才會生成,其實不然,traceroute 命令就是一個例外,它會使用 ICMP 的規則,故意制造一些能夠產生例外的場景,

traceroute 命令有兩大作用:

1)故意設定特殊的 TTL,來追蹤去往目的主機上沿途經過的路由器

具體來說,就是發送端主機會不斷的向接收端主機發送 UDP 報文,UDP 報文被封裝成 IP 資料報,同時將 TTL 從 1 開始按照順序遞增,

比如說,將 TTL 設定 為 1,那么遇到第一個路由器的時候,這個 IP 資料報就會被丟棄,接著回傳 ICMP 差錯報文,型別是 ICMP 超時訊息

接下來將 TTL 設定為 2,第一個路由器過了,遇到第二個路由器時這個 IP 資料報就會被丟棄,接著回傳ICMP 差錯報文,

......

這樣,traceroute 就拿到了所有路由器 IP,

那到這里其實還有一個問題,怎么知道資料到底有沒有到達目的主機呢

traceroute 是基于 UDP 傳輸的,那自然是需要指定一個埠號的,traceroute 會選擇一個不可能的值作為 UDP 的埠號,

這樣,當資料到達目的主機時,就會發現埠對不上,于是路由器會產生一份 ICMP 目標不可達訊息,其代碼是 3,即埠不可達

當發送端主機接收這份埠不可達的 ICMP 報文時,就知道目的主機成功收到了資料,

2)故意設定不分片,從而確定路徑的最大傳輸單元 MTU

某些情況下我們并不知道路徑的 MTU 大小,所以我們需要某種手段去獲取 MTU,才能控制發送的資料包的大小,

發送端主機要做的作業很簡單,就是像往常一樣發送 IP 資料報,但是將 IP 首部的分片禁止標志位置為 1,

這樣,如果 IP 資料報的長度超過了 MTU,該資料報會被路由器直接丟棄,并且給發送端主機發送 ICMP 目標不可達訊息,其代碼為 4,即需要進行分片但設定了不分片位

這樣,發送端主機每次收到 ICMP 需要進行分片但設定了不分片位訊息時就減小 IP 資料報的長度,直到順利到達目標主機,

?? 關注公眾號 | 飛天小牛肉,即時獲取更新

  • 博主東南大學碩士在讀,攜程 Java 后臺開發暑期實習生,利用課余時間運營一個公眾號『 飛天小牛肉 』,2020/12/29 日開通,專注分享計算機基礎(資料結構 + 演算法 + 計算機網路 + 資料庫 + 作業系統 + Linux)、Java 技術堆疊等相關原創技術好文,本公眾號的目的就是讓大家可以快速掌握重點知識,有的放矢,關注公眾號第一時間獲取文章更新,成長的路上我們一起進步
  • 并推薦個人維護的開源教程類專案: CS-Wiki(Gitee 推薦專案,現已累計 1.6k+ star), 致力打造完善的后端知識體系,在技術的路上少走彎路,歡迎各位小伙伴前來交流學習 ~ ??
  • 如果各位小伙伴春招秋招沒有拿得出手的專案的話,可以參考我寫的一個專案「開源社區系統 Echo」Gitee 官方推薦專案,目前已累計 700+ star,基于 SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ... 并提供詳細的開發檔案和配套教程,公眾號后臺回復 Echo 可以獲取配套教程,目前尚在更新中,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/281125.html

標籤:其他

上一篇:Python系列爬蟲之抓取并分析拉勾網招聘資料

下一篇:Python串列介紹

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more