1. 程式人生 > >我畫了 40 張圖就是為了讓你搞懂計算機網路層

我畫了 40 張圖就是為了讓你搞懂計算機網路層

> 我把自己以往的文章彙總成為了 Github ,歡迎各位大佬 star > https://github.com/crisxuan/bestJavaer ![](https://s3.ax1x.com/2021/01/03/spO8e0.png) 前面我們學習了運輸層如何為客戶端和伺服器輸送資料的,提供程序端到端的通訊。那麼下面我們將學習網路層實際上是怎樣實現主機到主機的通訊服務的。**幾乎每個端系統都有網路層這一部分**。所以,網路層必然是很複雜的。下面我將花費大量篇幅來介紹一下計算機網路層的知識。 ## 網路層概述 網路層是 OSI 參考模型的第三層,它位於傳輸層和鏈路層之間,網路層的主要目的是實現兩個端系統之間透明的資料傳輸。
網路層的作用從表面看上去非常簡單,即將`分組`從一臺主機移動到另外一臺主機。為了實現這個功能,網路層需要兩種功能 * `轉發`:因為在網際網路中有很多`路由器`的存在,而路由器是構成網際網路的根本,路由器最重要的一個功能就是`分組轉發`,當一個分組到達某路由器的一條輸入鏈路時,該路由器會將分組移動到適當的輸出鏈路。轉發是在資料平面中實現的唯一功能。 >在網路中存在兩種平面的選擇 > >* 資料平面(data plane):負責轉發網路流量,如路由器交換機中的轉發表(我們後面會說)。 >* 控制平面(control plane):控制網路的行為,比如網路路徑的選擇。 * `路由選擇`:當分組由傳送方流向接收方時,網路層必須選擇這些分組的路徑。計算這些路徑選擇的演算法被稱為 `路由選擇演算法(routing algorithm)`。 也就是說,**轉發是指將分組從一個輸入鏈路轉移到適當輸出鏈路介面的路由器本地動作**。而路由選擇是指確定分組從源到目的地所定位的路徑的選擇。我們後面會經常提到轉發和路由選擇這兩個名詞。 >
那麼此處就有一個問題,路由器怎麼知道有哪些路徑可以選擇呢? 每臺路由器都有一個關鍵的概念就是 `轉發表(forwarding table)`。路由器通過檢查資料包標頭中欄位的值,來定位轉發表中的項來實現轉發。標頭中的值即對應著轉發表中的值,這個值指出了分組將被轉發的路由器輸出鏈路。如下圖所示 ![](https://s3.ax1x.com/2020/12/22/rBOTHS.png) 上圖中有一個 1001 分組到達路由器後,首先會在轉發表中進行索引,然後由路由選擇演算法決定分組要走的路徑。每臺路由器都有兩種功能:**轉發和路由選擇**。下 面我們就來聊一聊路由器的工作原理。 ## 路由器工作原理 下面是一個路由器體系結構圖,路由器主要是由 4 個元件構成的 ![](https://s3.ax1x.com/2020/12/22/rBOoB8.png) * 輸入埠:`輸入埠(input port)`有很多功能。`線路終端功能`和`資料鏈路處理`功能,這兩個功能實現了路由器的單個輸入鏈路相關聯的物理層和資料鏈路層。`輸入埠查詢/轉發功能`對路由器的交換功能來說至關重要,由路由器的交換結構來決定輸出埠,具體來講應該是查詢轉發表來確定的。 * 交換結構:`交換結構(Switching fabric)`就是將路由器的輸入埠連線到它的輸出埠。這種交換結構相當於是路由器內部的網路。 * 輸出埠:`輸出埠(Output ports)` 通過交換結構轉發分組,並通過物理層和資料鏈路層的功能傳輸分組,因此,輸出埠作為輸入埠執行反向資料鏈接和物理層功能。 * 路由選擇處理器:`路由選擇處理器(Routing processor)` 在路由器內執行路由協議,維護路由表並執行網路管理功能。 上面只是這幾個元件的簡單介紹,其實這幾個元件的組成並不像描述的那樣簡單,下面我們就來深入聊一聊這幾個元件。 ### 輸入埠 上面介紹了輸入埠有很多功能,包括線路終端、資料處理、查詢轉發,其實這些功能在輸入埠的內部有相應的模組,輸入埠的內部實現如下圖所示 ![](https://s3.ax1x.com/2020/12/22/rBOhct.png) 每個輸入埠中都有一個路由處理器維護的**路由表的副本**,根據路由處理器進行更新。這個路由表的副本能 夠使每個輸入埠進行切換,而無需經過路由處理器統一處理。這是一種`分散式`的切換,這種方式避免了路 由選擇器統一處理造成轉發瓶頸。 在輸入埠處理能力有限的路由器中,輸入埠不會進行交換功能,而是由路由處理器統一處理,然後根據 路由表查詢並將資料包轉發到相應的輸出埠。 >
一般這種路由器不是單獨的路由器,而是工作站或者伺服器充當的路由,這種路由器內部中,路由處理器其實就是 `CPU`,而輸入埠其實只是`網絡卡`。 輸入埠會根據轉發表定位輸出埠,然後再會進行分組轉發,那麼現在就有一個問題,是不是每一個分組都有自己的一條鏈路呢?如果分組數量非常大,到達億級的話,也會有億個輸出埠路徑嗎? 我們的潛意識中顯然不是的,來看下面一個例子。 下面是三個輸入埠對應了轉發表中的三個輸出鏈路的示例 ![](https://s3.ax1x.com/2020/12/22/rBOHAg.png) 可以看到,對於這個例子來說,路由器轉發表中不需要那麼多條鏈路,只需要四條就夠,即對應輸出鏈路 0 1 2 3 。也就是說,能夠使用 4 個轉發表就可以實現億級鏈路。 > 如何實現呢? 使用這種風格的轉發表,路由器分組的地址 `字首(prefix)` 會與該表中的表項進行匹配。 ![](https://s3.ax1x.com/2020/12/22/rBObNQ.png) 如果存在一個匹配項,那麼就會轉發到對應的鏈路上,可能不好理解,我舉個例子來說吧。 比如這時有一個分組是 11000011 10010101 00010000 0001100 到達,因為這個分組與 11000011 10010101 00010000 相匹配,所以路由器會轉發到 0 鏈路介面上。如果一個字首不匹配上面三個輸出鏈路中的一種,那麼路由器將向鏈路介面 3 進行轉發。 路由匹配遵循 `最長字首原則(longest prefix matching rule)`,最長匹配原則故名思義就是如果有兩個匹配項一個長一個短的話,就匹配最長的。 一旦通過查詢功能確定了分組的輸出埠後,那麼該分組就會進入交換結構。在進入交換結構時,如果交換結構正在被使用,就會阻塞新到的分組,等到交換結構排程新的分組。 ### 交換結構 交換結構是路由器的核心功能,通過交換功能把分組從輸入埠轉發至輸出埠,這就是交換結構的主要功能。交換結構有多種形式,主要分為 **通過記憶體交換、通過匯流排交換、通過網際網路絡進行交換**,下面我們分開來探討一下。 * 經過記憶體交換:最開始的傳統計算機就是使用`記憶體交換`的,在輸入埠和輸出埠之間是通過 CPU 進行的。輸入埠和輸出埠的功能就好像傳統作業系統中的 I/O 裝置一樣。當一個分組到達輸入埠時,這個埠會首先以`中斷` 的方式向路由選擇器發出訊號,將分組從輸入埠拷貝到記憶體中。然後,路由選擇處理器從分組首部中提取目標地址,在轉發表中找出適當的輸出埠進行轉發,同時將分組複製到輸出埠的快取中。 >這裡需要注意一點,如果記憶體頻寬以每秒讀取或者寫入 B 個數據包,那麼總的交換機吞吐量(資料包從輸入埠到輸出埠的總速率) 必須小於 B/2。 ![](https://s3.ax1x.com/2020/12/22/rBOqhj.png) * 經過匯流排交換:在這種處理方式中,匯流排經由輸入埠直接將分組傳送到輸出埠,中間不需要路由選擇器的干預。匯流排的工作流程如下:輸入埠給分組分配一個`標籤`,然後分組經由匯流排傳送給所有的輸出埠,每個輸出埠都會判斷標籤中的埠和自己的是否匹配,如果匹配的話,那麼這個輸出埠就會把標籤拆掉,這個標籤只用於交換機內部跨越匯流排。如果同時有 `多個` 分組到達路由器的話,那麼只有一個分組能夠被處理,其他分組需要再進入交換結構前等待。 ![](https://s3.ax1x.com/2020/12/22/rBOO9s.png) * 經過網際網路絡交換:克服單一、共享式匯流排頻寬限制的一種方法是使用一個更復雜的網際網路絡。如下圖所示 ![](https://s3.ax1x.com/2020/12/22/rBOX3n.png) 每條垂直的的匯流排在交叉點與每條水平的匯流排交叉,交叉點通過交換結構控制器能夠在任何時候開啟和閉合。當分組到達輸入埠 A 時,如果需要轉發到埠 X,交換機控制器會閉合 A 到 X 交叉部分的交叉點,然後埠 A 在總線上進行分組轉發。這種網路互聯式的交換結構是 `非阻塞的(non-blocking)`的,也就是說 A -> X 的交叉點閉合不會影響 B -> Y 的鏈路。如果來自兩個不同輸入埠的兩個分組其目的地為相同的輸出埠的話,這種情況下只能有一個分組被交換,另外一個分組必須進行等待。 ### 輸出埠處理 如下圖所示,輸出埠處理取出已經存放在輸出埠記憶體中的分組並將其傳送到輸出鏈路上。包括選擇和去除排隊的分組進行傳輸,執行所需的鏈路層和物理層的功能。 ![](https://s3.ax1x.com/2020/12/22/rBOjcq.png) 在輸入埠中有等待進入交換的排隊佇列,而在輸出埠中有等待轉發的排隊佇列,排隊的位置和程度取決於**流量負載、交換結構**的相對頻率和線路速率。 隨著佇列的不斷增加,會導致路由器的快取空間被耗盡,進而使沒有記憶體可以儲存溢位的佇列,致使分組出現`丟包(packet loss)`,這就是我們說的在網路中丟包或者被路由器丟棄。 ## 何時出現排隊 下面我們通過輸入埠的排隊佇列和輸出埠的排隊佇列來介紹一下可能出現的排隊情況。 ### 輸入佇列 如果交換結構的處理速度沒有輸入佇列到達的速度快,在這種情況下,輸入埠將會出現排隊情況,到達交換結構前的分組會加入輸入埠佇列中,以等待通過交換結構傳送到輸出埠。 為了描述清楚輸入佇列,我們假設以下情況: * 使用網路互聯的交換方式; * 假定所有鏈路的速度相同; * 在鏈路中一個分組由輸入埠交換到輸出埠所花的時間相同,從任意一個輸入埠傳送到給定的輸出埠; * 分組按照 FCFS 的方式,只要輸出埠不同,就可以進行並行傳送。但是如果位於任意兩個輸入埠中的分組是發往同一個目的地的,那麼其中的一個分組將被阻塞,而且必須在輸入佇列中等待,因為交換結構一次只能傳輸一個到指定埠。 如下圖所示 ![](https://s3.ax1x.com/2020/12/22/rBOvj0.png) 在 A 佇列中,輸入佇列中的兩個分組會發送至同一個目的地 X,假設在交換結構正要傳送 A 中的分組,在這個時候,C 佇列中也有一個分組傳送至 X,在這種情況下,C 中傳送至 X 的分組將會等待,不僅如此,C 佇列中傳送至 Y 輸出埠的分組也會等待,即使 Y 中沒有出現競爭的情況。這種現象叫做 `線路前部阻塞(Head-Of-The-Line, HOL)` 。 ### 輸出佇列 我們下面討論輸出佇列中出現等待的情況。假設交換速率要比輸入/輸出的傳輸速率快很多,而且有 N 個輸入分組的目的地是轉發至相同的輸出埠。在這種情況下,在向輸出鏈路傳送分組的過程中,將會有 N 個新分組到達傳輸埠。因為輸出埠在一個單位時間內只能傳輸一個分組,那麼這 N 個分組將會等待。然而在等待 N 個分組被處理的過程中,同時又有 N 個分組到達,所以 ,分組佇列能夠在輸出埠形成。這種情況下最終會因為分組數量變的足夠大,從而`耗盡` 輸出埠的可用記憶體。 如果沒有足夠的記憶體來快取分組的話,就必須考慮其他的方式,主要有兩種:一種是丟失分組,採用 `棄尾(drop-tail)` 的方法;一種是刪除一個或多個已經排隊的分組,從而來為新的分組騰出空間。 >網路層的策略對 TCP 擁塞控制影響很大的就是路由器的分組丟棄策略。在最簡單的情況下,路由器的佇列通常都是按照 FCFS 的規則處理到來的分組。由於佇列長度總是有限的,因此當佇列已經滿了的時候,以後再到達的所有分組(如果能夠繼續排隊,這些分組都將排在佇列的尾部)將都被丟棄。這就叫做尾部丟棄策略。 通常情況下,在緩衝填滿之前將其丟棄是更好的策略。 ![](https://s3.ax1x.com/2020/12/22/rBOzuV.png) 如上圖所示,A B C 每個輸入埠都到達了一個分組,而且這個分組都是發往 X 的,同一時間只能處理一個分組,然後這時,又有兩個分組分別由 A B 發往 X,所以此時有 4 個分組在 X 中進行等待。 ![](https://s3.ax1x.com/2020/12/22/rBXpHU.png) 等上一個分組被轉發完成後,輸出埠就會選擇在剩下的分組中根據 `分組排程(packet scheduleer)` 選擇一個分組來進行傳輸,我們下面就會聊到分組傳輸。 ## 分組排程 現在我們來討論一下分組排程次序的問題,即排隊的分組如何經輸出鏈路傳輸的問題。我們生活中有無數排隊的例子,但是我們生活中一般的排隊演算法都是 `先來先服務(FCFS)`,也是`先進先出(FIFO)`。 ### 先進先出 先進先出就對映為資料結構中的`佇列`,只不過它現在是鏈路排程規則的排隊模型。 ![](https://s3.ax1x.com/2020/12/22/rBXSBT.png) FIFO 排程規則按照分組到達輸出鏈路佇列的相同次序來選擇分組,先到達佇列的分組將先會被轉發。在這種抽象模型中,如果佇列已滿,那麼棄尾的分組將是佇列末尾的後面一個。 ### 優先順序排隊 優先順序排隊是先進先出排隊的改良版本,到達輸出鏈路的分組被分類放入輸出佇列中的優先權類,如下圖所示 ![](https://s3.ax1x.com/2020/12/22/rBXCEF.png) 通常情況下,每個優先順序不同的分組有自己的優先順序類,每個優先順序類有自己的佇列,分組傳輸會首先從優先順序高的佇列中進行,在同一類優先順序的分組之間的選擇通常是以 FIFO 的方式完成。 ### 迴圈加權公平排隊 在`迴圈加權公平規則(round robin queuing discipline)` 下,分組像使用優先順序那樣被分類。然而,在類之間卻不存在嚴格的服務優先權。迴圈排程器在這些類之間迴圈輪流提供服務。如下圖所示 ![](https://s3.ax1x.com/2020/12/22/rBXPN4.png) 在迴圈加權公平排隊中,類 1 的分組被傳輸,接著是類 2 的分組,最後是類 3 的分組,這算是一個迴圈,然後接下來又重新開始,又從 1 -> 2 -> 3 這個順序進行輪詢。每個佇列也是一個先入先出的佇列。 這是一種所謂的`保持工作排隊(work-conserving queuing)` 的規則,就是說如果輪詢的過程中發現有空佇列,輸出埠不會等待分組,而是繼續輪詢下面的佇列。 ## IP 協議 路由器對分組進行轉發後,就會把資料包傳到網路上,資料包最終是要傳遞到客戶端或者伺服器上的,那麼資料包怎麼知道要發往哪裡呢?起到關鍵作用的就是 IP 協議。 IP 主要分為三個部分,分別是 **IP 定址、路由和分包組包**。下面我們主要圍繞這三點進行闡述。 ### IP 地址 既然一個數據包要在網路上傳輸,那麼肯定需要知道這個資料包到底發往哪裡,也就是說需要一個目標地址資訊,**IP 地址就是連線網路中的所有主機進行通訊的目標地址**,因此,在網路上的每個主機都需要有自己的 IP 地址。 ![](https://s3.ax1x.com/2020/12/22/rBXi4J.png) 在 IP 資料報傳送的鏈路中,有可能鏈路非常長,比如說由中國發往美國的一個數據報,由於網路抖動等一些意外因素可能會導致資料報丟失,這時我們在這條鏈路中會放入一些 `中轉站`,一方面能夠確保資料報是否丟失,另一方面能夠控制資料報的轉發,這個中轉站就是我們前面聊過的路由器,這個轉發過程就是 `路由控制`。 `路由控制(Routing)` 是指將分組資料傳送到最終目標地址的功能,即使網路複雜多變,也能夠通過路由控制到達目標地址。因此,一個數據報能否到達目標主機,關鍵就在於路由器的控制。 這裡有一個名詞,就是 `跳`,因為在一條鏈路中可能會佈滿很多路由器,路由器和路由器之間的資料報傳送就是跳,比如你和隔壁老王通訊,中間就可能會經過路由器 A-> 路由器 B -> 路由器 C 。 >那麼一跳的範圍有多大呢? **一跳是指從源 MAC 地址到目標 MAC 地址之間傳輸幀的區間**,這裡引出一個新的名詞,MAC 地址是啥? MAC 地址指的就是計算機的`實體地址(Physical Address)`,它是用來確認網路裝置位置的地址。在 OSI 網路模型中,網路層負責 IP 地址的定位,而資料鏈路層負責 MAC 地址的定位。MAC 地址用於在網路中唯一標示一個網絡卡,一臺裝置若有一或多個網絡卡,則每個網絡卡都需要並會有一個唯一的 MAC 地址,也就是說 MAC 地址和網絡卡是緊密聯絡在一起的。 路由器的每一跳都需要詢問當前中轉的路由器,下一跳應該跳到哪裡,從而跳轉到目標地址。而不是資料報剛開始傳送後,網路中所有的通路都會顯示出來,這種多次跳轉也叫做`多跳路由`。 #### IP 地址定義 現如今有兩個版本的 IP 地址,IPv4 和 IPv6,我們首先探討一下現如今還在廣泛使用的 IPv4 地址,後面再考慮 IPv6 。 IPv4 由 32 位正整數來表示,在計算機內部會轉化為二進位制來處理,但是二進位制不符合人類閱讀的習慣,所以我們根據`易讀性`的原則把 32 位的 IP 地址以 8 位為一組,分成四組,每組之間以 `.` 進行分割,再將每組轉換為十進位制數。如下圖所示 ![](https://s3.ax1x.com/2020/12/22/rBXkC9.png) 那麼上面這個 32 位的 IP 地址就會被轉換為十進位制的 156.197.1.1。 除此之外,從圖中我們還可以得到如下資訊 每個這樣 8 位位一組的數字,自然是非負數,其取值範圍是 [0,255]。 IP 地址的總個數有 2^32 次冪個,這個數值算下來是 `4294967296` ,大概能允許 43 億臺裝置連線到網路。實際上真的如此嗎? 實際上 IP 不會以主機的個數來配置的,而是根據裝置上的 `網絡卡(NIC)` 進行配置,每一塊網絡卡都會設定一個或者多個 IP 地址,而且通常一臺路由器會有至少兩塊網絡卡,所以可以設定兩個以上的 IP 地址,所以主機的數量遠遠達不到 43 億。 ![](https://s3.ax1x.com/2020/12/22/rBXA3R.png) #### IP 地址構造和分類 IP 地址由 `網路標識` 和 `主機標識` 兩部分組成,網路標識代表著網路地址,主機標識代表著主機地址。網路標識在資料鏈路的每個段配置不同的值。網路標識必須保證相互連線的每個段的地址都不重複。而相同段內相連的主機必須有相同的網路地址。IP 地址的 `主機標識` 則不允許在同一網段內重複出現。 舉個例子來說:比如說我在石家莊(好像不用比如昂),我所在的小區的某一棟樓就相當於是網路標識,某一棟樓的第幾戶就相當於是我的主機標識,當然如果你有整棟樓的話,那就當我沒說。你可以通過xx省xx市xx區xx路xx小區xx棟來定位我的網路標識,這一棟的第幾戶就相當於是我的網路標識。 IP 地址分為四類,分別是 **A類、B類、C類、D類、E類**,它會根據 IP 地址中的第 1 位到第 4 位的位元對網路標識和主機標識進行分類。 * `A 類`:(1.0.0.0 - 126.0.0.0)(預設子網掩碼:255.0.0.0 或 0xFF000000)第一個位元組為網路號,後三個位元組為主機號。該類 IP 地址的最前面為 0 ,所以地址的網路號取值於 1~126 之間。一般用於大型網路。 * `B 類`:(128.0.0.0 - 191.255.0.0)(預設子網掩碼:255.255.0.0 或 0xFFFF0000)前兩個位元組為網路號,後兩個位元組為主機號。該類 IP 地址的最前面為 10 ,所以地址的網路號取值於 128~191 之間。一般用於中等規模網路。 * `C 類`:(192.0.0.0 - 223.255.255.0)(子網掩碼:255.255.255.0 或 0xFFFFFF00)前三個位元組為網路號,最後一個位元組為主機號。該類 IP 地址的最前面為 110 ,所以地址的網路號取值於 192~223 之間。一般用於小型網路。 * `D 類`:是多播地址。該類 IP 地址的最前面為 1110 ,所以地址的網路號取值於 224~239 之間。一般用於多路廣播使用者。 * `E 類`:是保留地址。該類 IP 地址的最前面為 1111 ,所以地址的網路號取值於 240~255 之間。 為了方便理解,我畫了一張 IP 地址分類圖,如下所示 ![](https://s3.ax1x.com/2020/12/22/rBXEg1.png) 根據不同的 IP 範圍,有下面不同的地總空間分類 ![](https://s3.ax1x.com/2020/12/22/rBXVjx.png) #### 子網掩碼 `子網掩碼(subnet mask)` 又叫做網路掩碼,它是一種用來指明一個 IP 地址的哪些位標識的是主機所在的網路。子網掩碼是一個 32位 地址,用於遮蔽 IP 地址的一部分以區別網路標識和主機標識。 一個 IP 地址只要確定了其分類,也就確定了它的網路標識和主機標識,由此,各個分類所表示的網路標識範圍如下 ![](https://s3.ax1x.com/2020/12/22/rBXmDK.png) 用 `1` 表示 IP 網路地址的位元範圍,`0` 表示 IP 主機地址的範圍。將他們用十進位制表示,那麼這三類的表示如下 ![](https://s3.ax1x.com/2020/12/22/rBXeu6.png) #### 保留地址 在IPv4 的幾類地址中,有幾個保留的地址空間不能在網際網路上使用。這些地址用於特殊目的,不能在區域網外部路由。 ![](https://s3.ax1x.com/2020/12/22/rBXnHO.png) ### IP 協議版本 目前,全球 Internet 中共存有兩個IP版本:`IP 版本 4(IPv4)`和 `IP 版本6(IPv6)`。 IP 地址由二進位制值組成,可驅動 Internet 上所有資料的路由。 IPv4 地址的長度為 32 位,而 IPv6 地址的長度為 128 位。 Internet IP 資源由 `Internet 分配號碼機構(IANA)`分配給區域 Internet 登錄檔(RIR),例如 APNIC,該機構負責根 DNS ,IP 定址和其他 Internet 協議資源。 下面我們就一起認識一下 IP 協議中非常重要的兩個版本 IPv4 和 IPv6。 ### IPv4 IPv4 的全稱是 `Internet Protocol version 4`,是 Internet 協議的第四版。IPv4 是一種無連線的協議,這個協議會盡最大努力交付資料包,也就是說它不能保證任何資料包能到達目的地,也不能保證所有的資料包都會按照正確的順序到達目標主機,這些都是由上層比如傳輸控制協議控制的。也就是說,單從 IP 看來,這是一個不可靠的協議。 >前面我們講過網路層分組被稱為 `資料報`,所以我們接下來的敘述也會圍繞著資料報展開。 IPv4 的資料報格式如下 ![](https://s3.ax1x.com/2020/12/22/rBXKED.png) IPv4 資料報中的關鍵字及其解釋 * `版本欄位(Version)`佔用 4 bit,通訊雙方使用的版本必須一致,對於 IPv4 版本來說,欄位值是 4。 * `首部長度(Internet Header Length)` 佔用 4 bit,首部長度說明首部有多少 32 位(4 位元組)。由於 IPv4 首部可能包含不確定的選項,因此這個欄位被用來確定資料的偏移量。大多數 IP 不包含這個選項,所以一般首部長度設定為 5, 資料報為 20 位元組 。 * `服務型別(Differential Services Codepoint,DSCP)` 佔用 6 bit,以便使用不同的 IP 資料報,比如一些低時延、高吞吐量和可靠性的資料報。服務型別如下表所示 * `擁塞通告(Explicit Congestion Notification,ECN)` 佔用 2 bit,它允許在不丟棄報文的同時通知對方網路擁塞的發生。ECN 是一種可選的功能,僅當兩端都支援並希望使用,且底層網路支援時才被使用。 最開始 DSCP 和 ECN 統稱為 TOS,也就是區分服務,但是後來被細化為了 DSCP 和 ECN。 * `資料報長度(Total Length)` 佔用 16 bit,這 16 位是包括在資料在內的總長度,理論上資料報的總長度為 2 的 16 次冪 - 1,最大長度是 65535 位元組,但是實際上資料報很少有超過 1500 位元組的。IP 規定所有主機都必須支援最小 576 位元組的報文,但大多數現代主機支援更大的報文。當下層的資料鏈路協議的`最大傳輸單元(MTU)`欄位的值小於 IP 報文長度時,報文就必須被分片。 * `識別符號(Identification)` 佔用 16 bit,這個欄位用來標識所有的分片,因為分片不一定會按序到達,所以到達目標主機的所有分片會進行重組,每產生一個數據報,計數器加1,並賦值給此欄位。 * `標誌(Flags)` 佔用 3 bit,標誌用於控制和識別分片,這 3 位分別是 * 0 位:保留,必須為0; * 1 位:`禁止分片(Don’t Fragment,DF)`,當 DF = 0 時才允許分片; * 2 位:`更多分片(More Fragment,MF)`,MF = 1 代表後面還有分片,MF = 0 代表已經是最後一個分片。 如果 DF 標誌被設定為 1 ,但是路由要求必須進行分片,那麼這條資料報回丟棄 * `分片偏移(Fragment Offset)` 佔用 13 位,它指明瞭每個分片相對於原始報文開頭的偏移量,以 8 位元組作單位。 * `存活時間(Time To Live,TTL)` 佔用 8 位,存活時間避免報文在網際網路中`迷失`,比如陷入路由環路。存活時間以秒為單位,但小於一秒的時間均向上取整到一秒。在現實中,這實際上成了一個跳數計數器:報文經過的每個路由器都將此欄位減 1,當此欄位等於 0 時,報文不再向下一跳傳送並被丟棄,這個欄位最大值是 255。 * `協議(Protocol)` 佔用 8 位,這個欄位定義了報文資料區使用的協議。協議內容可以在 https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml 官網上獲取。 * `首部校驗和(Header Checksum)` 佔用 16 位,首部校驗和會對欄位進行糾錯檢查,在每一跳中,路由器都要重新計算出的首部檢驗和並與此欄位進行比對,如果不一致,此報文將會被丟棄。 * `源地址(Source address)` 佔用 32 位,它是 IPv4 地址的構成條件,源地址指的是資料報的傳送方 * `目的地址(Destination address)`佔用 32 位,它是 IPv4 地址的構成條件,目標地址指的是資料報的接收方 * `選項(Options)` 是附加欄位,選項欄位佔用 1 - 40 個位元組不等,一般會跟在目的地址之後。如果首部長度 > 5,就應該考慮選項欄位。 * `資料` 不是首部的一部分,因此並不被包含在首部檢驗和中。 在 IP 傳送的過程中,每個資料報的大小是不同的,每個鏈路層協議能承載的網路層分組也不一樣,有的協議能夠承載大資料報,有的卻只能承載很小的資料報,不同的鏈路層能夠承載的資料報大小如下。 ![](https://s3.ax1x.com/2020/12/22/rBXQ4H.png) #### IPv4 分片 一個鏈路層幀能承載的最大資料量叫做`最大傳輸單元(Maximum Transmission Unit, MTU)`,每個 IP 資料報封裝在鏈路層幀中從一臺路由器傳到下一臺路由器。因為每個鏈路層所支援的最大 MTU 不一樣,當資料報的大小超過 MTU 後,會在鏈路層進行分片,每個資料報會在鏈路層單獨封裝,每個較小的片都被稱為 `片(fragement)`。 ![](https://s3.ax1x.com/2020/12/22/rBX38A.png) 每個片在到達目的地後會進行重組,準確的來說是在運輸層之前會進行重組,TCP 和 UDP 都會希望傳送完整的、未分片的報文,出於效能的原因,分片重組不會在路由器中進行,而是會在目標主機中進行重組。 當目標主機收到從傳送端傳送過來的資料報後,它需要確定這些資料報中的分片是否是由源資料報分片傳遞過來的,如果是的話,還需要確定何時收到了分片中的`最後一片`,並且這些片會如何拼接一起成為資料報。 針對這些潛在的問題,IPv4 設計者將 **標識、標誌和片偏移**放在 IP 資料報首部中。當生成一個數據報時,傳送主機會為該資料報設定源和目的地址的同時貼上`標識號`。傳送主機通常將它傳送的每個資料報的標識 + 1。當某路由器需要對一個數據報分片時,形成的每個資料報具有初始資料報的**源地址、目標地址和標識號**。當目的地從同一傳送主機收到一系列資料報時,它能夠檢查資料報的標識號以確定哪些資料是由源資料報傳送過來的。由於 IP 是一種不可靠的服務,分片可能會在網路中丟失,鑑於這種情況,通常會把分片的最後一個位元設定為 0 ,其他分片設定為 1,同時使用偏移欄位指定分片應該在資料報的哪個位置。 #### IPv4 定址 IPv4 支援三種不同型別的定址模式,分別是 * 單播定址模式:在這種模式下,資料只發送到一個目的地的主機。 ![](https://s3.ax1x.com/2020/12/22/rBX1Cd.png) * 廣播定址模式:在此模式下,資料包將被定址到網段中的所有主機。這裡客戶端傳送一個數據包,由所有伺服器接收: ![](https://s3.ax1x.com/2020/12/22/rBO4jP.png) * 組播定址模式:此模式是前兩種模式的混合,即傳送的資料包既不指向單個主機也不指定段上的所有主機 ![](https://s3.ax1x.com/2020/12/22/rBxVvn.png) ### IPv6 隨著端系統接入的越來越多,IPv4 已經無法滿足分配了,所以,IPv6 應運而生,IPv6 就是為了解決 IPv4 的地址耗盡問題而被標準化的網際協議。IPv4 的地址長度為 4 個 8 位元組,即 32 位元, 而 IPv6 的地址長度是原來的四倍,也就是 128 位元,一般寫成 8 個 16 位位元組。 從 IPv4 切換到 IPv6 及其耗時,需要將網路中所有的主機和路由器的 IP 地址進行設定,在網際網路不斷普及的今天,替換所有的 IP 是一個工作量及其龐大的任務。我們後面會說。 我們先來看一下 IPv6 的地址是怎樣的 ![](https://s3.ax1x.com/2020/12/22/rBxmD0.png) * `版本`與 IPv4 一樣,版本號由 4 bit 構成,IPv6 版本號的值為 6。 * `流量型別(Traffic Class)` 佔用 8 bit,它就相當於 IPv4 中的服務型別(Type Of Service)。 * `流標籤(Flow Label)` 佔用 20 bit,這 20 位元用於標識一條資料報的流,能夠對一條流中的某些資料報給出優先權,或者它能夠用來對來自某些應用的資料報給出更高的優先權,只有流標籤、源地址和目標地址一致時,才會被認為是一個流。 * `有效載荷長度(Payload Length)` 佔用 16 bit,這 16 位元值作為一個無符號整數,它給出了在 IPv6 資料報中跟在鼎昌 40 位元組資料報首部後面的位元組數量。 * `下一個首部(Next Header)` 佔用 8 bit,它用於標識資料報中的內容需要交付給哪個協議,是 TCP 協議還是 UDP 協議。 * `跳限制(Hop Limit)` 佔用 8 bit,這個欄位與 IPv4 的 TTL 意思相同。資料每經過一次路由就會減 1,減到 0 則會丟棄資料。 * `源地址(Source Address)` 佔用 128 bit (8 個 16 位 ),表示傳送端的 IP 地址。 * `目標地址(Destination Address)` 佔用 128 bit (8 個 16 位 ),表示接收端 IP 地址。 可以看到,相較於 IPv4 ,IPv6 取消了下面幾個欄位 * **識別符號、標誌和位元偏移**:IPv6 不允許在中間路由器上進行分片和重新組裝。這種操作只能在端系統上進行,IPv6 將這個功能放在端系統中,加快了網路中的轉發速度。 * **首部校驗和**:因為在運輸層和資料鏈路執行了報文段完整性校驗工作,IP 設計者大概覺得在網路層中有首部校驗和比較多餘,所以去掉了。**IP 更多專注的是快速處理分組資料**。 * **選項欄位**:選項欄位不再是標準 IP 首部的一部分了,但是它並沒有消失,而是可能出現在 IPv6 的擴充套件首部,也就是下一個首部中。 #### IPv6 擴充套件首部 IPv6 首部長度固定,無法將選項欄位加入其中,取而代之的是 IPv6 使用了`擴充套件首部` 擴充套件首部通常介於 IPv6 首部與 TCP/UDP 首部之間,在 IPv4 中可選長度固定為 40 位元組,在 IPv6 中沒有這樣的限制。IPv6 的擴充套件首部可以是任意長度。擴充套件首部中還可以包含擴充套件首部協議和下一個擴充套件欄位。 IPv6 首部中沒有標識和標誌欄位,**對 IP 進行分片時,需要使用到擴充套件首部**。 ![](https://s3.ax1x.com/2020/12/22/rBxEgs.png) 具體的擴充套件首部表如下所示 ![](https://s3.ax1x.com/2020/12/22/rBxnbV.png) 下面我們來看一下 IPv6 都有哪些特點 #### IPv6 特點 IPv6 的特點在 IPv4 中得以實現,但是即便實現了 IPv4 的作業系統,也未必實現了 IPv4 的所有功能。而 IPv6 卻將這些功能大眾化了,也就表明這些功能在 IPv6 已經進行了實現,這些功能主要有 * **地址空間變得更大**:這是 IPv6 最主要的一個特點,即支援更大的地址空間。 * **精簡報文結構**: IPv6 要比 IPv4 精簡很多,IPv4 的報文長度不固定,而且有一個不斷變化的選項欄位;IPv6 報文段固定,並且將選項欄位,分片的欄位移到了 IPv6 擴充套件頭中,這就極大的精簡了 IPv6 的報文結構。 * **實現了自動配置**:IPv6 支援其主機裝置的**狀態和無狀態**自動配置模式。這樣,沒有 `DHCP 伺服器`不會停止跨段通訊。 * **層次化的網路結構**: IPv6 不再像 IPv4 一樣按照 A、B、C等分類來劃分地址,而是通過 IANA -> RIR -> ISP 這樣的順序來分配的。IANA 是國際網際網路號碼分配機構,RIR 是區域網際網路註冊管理機構,ISP 是一些運營商(例如電信、移動、聯通)。 * **IPSec**:IPv6 的擴充套件報頭中有一個認證報頭、封裝安全淨載報頭,這兩個報頭是 IPsec 定義的。通過這兩個報頭網路層自己就可以實現端到端的安全,而無需像 IPv4 協議一樣需要其他協議的幫助。 * **支援任播**:IPv6 引入了一種新的定址方式,稱為任播定址。 #### IPv6 地址 我們知道,IPv6 地址長度為 128 位,他所能表示的範圍是 2 ^ 128 次冪,這個數字非常龐大,幾乎涵蓋了你能想到的所有主機和路由器,那麼 IPv6 該如何表示呢? 一般我們將 128 位元的 IP 地址以每 16 位元為一組,並用 `:` 號進行分隔,如果出現連續的 0 時還可以將 0 省略,並用 `::` 兩個冒號隔開,記住,一個 IP 地址只允許出現一次兩個連續的冒號。 下面是一些 IPv6 地址的示例 * 二進位制數表示 ![](https://s3.ax1x.com/2020/12/22/rBxA3j.png) * 用十六進位制數表示 ![](https://s3.ax1x.com/2020/12/22/rBxeuq.png) * 出現兩個冒號的情況 ![](https://s3.ax1x.com/2020/12/22/rBxKET.png) 如上圖所示,A120 和 4CD 中間的 0 被 :: 所取代了。 ## 如何從 IPv4 遷移到 IPv6 我們上面聊了聊 IPv4 和 IPv6 的報文格式、報文含義是什麼、以及 IPv4 和 IPv6 的特徵分別是什麼,看完上面的內容,你已經知道了 IPv4 現在馬上就變的不夠用了,而且隨著 IPv6 的不斷髮展和引用,雖然新型的 IPv6 可以做到`向後相容`,即 IPv6 可以收發 IPv4 的資料報,但是**已經部署的具有 IPv4 能力的系統卻不能夠處理 IPv6 資料報**。所以 IPv4 噬需遷移到 IPv6,遷移並不意味著將 IPv4 替換為 IPv6。這僅意味著同時啟用 IPv6 和 IPv4。 >那麼現在就有一個問題了,IPv4 如何遷移到 IPv6 呢?這就是我們接下來討論的重點。 ### 標誌 最簡單的方式就是設定一個標誌日,指定某個時間點和日期,此時全球的因特網機器都會在這時關機從 IPv4 遷移到 IPv6 。上一次重大的技術遷移是在 35 年前,但是很顯然,不用我過多解釋,這種情況肯定是 `不行的`。影響不可估量不說,如何保證全球人類都能知道如何設定自己的 IPv6 地址?一個設計數十億臺機器的標誌日現在是想都不敢想的。 ### 隧道技術 現在已經在實踐中使用的從 IPv4 遷移到 IPv6 的方法是 `隧道技術(tunneling)`。 >什麼是隧道技術呢? 隧道技術是一種使用網際網路絡的基礎設施在網路之間的傳輸資料的方式,使用隧道傳遞的資料可以是不同協議的資料幀或包。使用隧道技術所遵從的協議叫做`隧道協議(tunneling protocol)`。隧道協議會將這些協議的資料幀或包封裝在新的包頭中傳送。新的包頭提供了路由資訊,從而使封裝的負載資料能夠通過網際網路絡進行傳遞。 使用隧道技術一般都會建一個`隧道`,建隧道的依據如下: 比如兩個 IPv6 節點(下方 B、E)要使用 IPv6 資料報進行互動,但是它們是經由兩個 IPv4 的路由器進行互聯的。那麼我們就需要將 IPv6 節點和 IPv4 路由器組成一個隧道,如下圖所示 ![](https://s3.ax1x.com/2021/01/03/spq8cn.png) 藉助於隧道,在隧道傳送端的 IPv6 節點可將整個 IPv6 資料報放到一個 IPv4 資料報的`資料(有效載荷)` 欄位中,於是,IPv4 資料報的地址被設定為指向隧道接收端的 IPv6 的節點,比如上面的 E 節點。然後再發送給隧道中的第一個節點 C,如下所示 ![](https://s3.ax1x.com/2021/01/03/spqGXq.png) 隧道中間的 IPv4 提供路由,路由器不知道這個 IPv4 內部包含一個指向 IPv6 的地址。隧道接收端的 IPv6 節點收到 IPv4 資料報,會確定這個 IPv4 資料報含有一個 IPv6 資料報,通過觀察資料報長度和資料得知。然後取出 IPv6 資料報,再為 IPv6 提供路由,就好像兩個節點直接相連傳輸資料報一樣。 ## 總結 這篇文章是計算機網路系列的連載文章,這篇我們主要探討了網路層的相關知識、路由器的內部構造、路由器如何實現轉發的,IP 協議相關內容:包括 IP 地址、IPv4 和 IPv6 的相關內容,最後我們探討了如何使 IPv4 遷移到 IPv6 。 **另外,新增我的微信 becomecxuan,加入每日一題群,每天一道面試題分享,更多內容請參見我的 Github,[成為最好的 bestJavaer](https://github.com/crisxuan/bestJavaer/blob/master/network/computer-internet.md) **我自己肝了六本 PDF,微信搜尋「程式設計師cxuan」關注公眾號後,在後臺回覆 cxuan ,領取全部 PDF,這些 PDF 如下** [六本 PDF 連結](https://s3.ax1x.com/2020/11/30/DgOK6f.png) ![](https://img2020.cnblogs.com/blog/1515111/202011/1515111-20201130090550310-1032998206.png)