上篇文章 我們完整的描述了計算機五層模型中的『應用層』和『運輸層』,闡述了較為復雜的 TCP 協議的相關原理,相信大家一定也有所收獲,那么本篇將繼續五層模型的學習。
網絡層
『網絡層』其實解決的就是一個「轉發」的問題,通過傳說中的『IP 協議』划分了網絡范圍,即我沒有直接用網線和你連在一起,我也能通過你的 IP 分析出該怎么樣找到負責你的網關路由器,並通過你的網關路由給你傳輸數據報。
這就是『網絡層』做的事情,它本質上解決了兩台不存在於同一子網絡下的主機相互通信的問題。而『IP 協議』以及「如何解析 IP 的算法」算是兩個最核心的內容,我們首先看看這個『IP 協議』的相關概念。
以 IPv4 為例,使用 32 個比特位描述一個 IP 地址,所以理論上,整個 IPv4 可以提供 40 幾個億的 IP 地址,我們一般使用『點分十進制』來表示。
例如:11000001 00100000 11011000 00001001 的 IP 地址一般記為 193.32.216.9。
由此,我們解決了 IP 編址的問題,但是如何通過 IP 地址判斷出它所屬的子網絡呢?
引入一個名詞『子網掩碼』,它在形式上和 IP 地址一樣,使用 32 位比特位進行表述。其中,描述網絡部分的比特位全為 1,子網絡中的該主機編號部分全為 0 。
例如:子網掩碼 11111111.11111111.11111111.00000000,寫成十進制就是255.255.255.0。它明確了某個使用該子網掩碼的 IP 的前 24 位是它的子網絡部分,而后 8 位是該 IP 對應的主機在子網絡下的一個編號。
舉個例子:
IP 地址 172.16.254.1 所對應的子網掩碼為 255.255.255.0,那么我們只需要做『AND』運算這兩者即可得到該 IP 地址的網絡部分。
所以,這個 IP 地址的網絡號為 172.16.254 。
下面我們探討一個十分重要的協議,它解決了一個剛加入子網絡的主機如何獲取屬於它的 IP 地址的問題,這個協議叫,動態主機配置協議(DHCP)。
DHCP
一般來說,我們有兩種方式來配置主機的 IP 地址,一種是管理員手動的指定一個 IP 地址,當然,這樣的成本是非常高的,你不能配置了一個已經被分配出去的 IP地址,即管理員需要記錄所有已分配的 IP 地址。
另外一種呢,就是我們的 DHCP 協議,它允許新加入的主機自動獲取一個 IP 地址以及相關的子網掩碼和網關地址等。
默認情況下,路由器隔離廣播包,不會將收到的廣播包從一個子網發送到另一個子網。當 DHCP 服務器和客戶端不在同一個子網時,充當客戶端默認網關的路由器將廣播包發送到DHCP服務器所在的子網,這一功能就稱為 DHCP 中繼(DHCP Relay)。
也就是說,一個子網絡中應當有一台 DHCP 服務器,用於整個子網中 IP 地址的分配。但為每個子網都單獨配置一個 DHCP 服務器也有點「愚蠢」。
所以另一種解決辦法就是,某個網絡中的網關會知道負責該網絡的 DHCP 服務器在什么位置,IP 地址是什么,網關路由會負責轉發 DHCP 報文請求並返回響應的報文,這就叫 DHCP 中繼。
當然了,實際上現在的路由器本身就可以充當一個 DHCP 服務器,為其所在的子網提供動態地址獲取服務,所以往往也不需要轉發那樣麻煩。
而完整的 DHCP 請求與響應的過程則是這樣的:
第一步:
DHCP 服務器發現。 這個階段的首要任務是,找到當前網絡中 DHCP 服務器的位置,並且整個 DHCP 報文的交換是基於 UDP/IP 協議的,向目的端口 67 發送。
本機由於沒有 IP 地址,所以 IP 數據報中的『源地址』為「0.0.0.0」,『目的地址』為「255.255.255.255」。
這樣在鏈路層廣播該數據報的時候,同一子網絡下的所有主機都會接受該數據報,但只有 DHCP 服務器會響應這個請求。
於是如果路由器本身就是一個 DHCP 服務器的話,那將進入第二步,否則路由器將分組轉發到 DHCP 服務器所在的網絡內。
第二步:
DHCP 服務器提供。 DHCP 服務器,無論是位於外網或是網關路由本身,在收到一個『發現報文』后,將響應一個『提供報文』。
該報文中將包含,推薦客戶使用的 IP 地址、子網掩碼、IP 地址租用周期等信息。
第三步:
DHCP 請求。這其實是一個選擇階段,客戶端主機確認服務器推薦的參數,決定使用,於是依然以廣播的形式發送請求向服務器確認。
第四步:
DHCP ACK。收到客戶端主機發來的確認請求后,服務器將實際從 IP 池中分配出一塊 IP 地址出來,並返回客戶端確認信息的 ACK。
從此之后,該主機算是獲得了一塊可用的 IP 地址了,終於加入了網絡。
除此之外,還有一個細節不知道大家日常有沒有留心,就是我們對於同一個子網絡,IP 地址基本總是一樣的,並沒有因為每次開機后連入網絡而被分配不同的 IP。
這一點算是 DHCP 協議的一個約定了,當某台主機第一次加入某個子網絡,它將從 DHCP 服務器獲取一個全新的 IP 地址。
而以后該主機重新加入到該網絡時,將直接進入 DHCP 請求的第三步,將主機上次使用的參數發給服務器,確認是否可用。而一般情況下服務器會同意並按照你的要求分配出去一塊 IP 地址,這也是為什么你每次使用的幾乎是同一 IP。
講完了 DHCP 動態獲取 IP 地址,接着我們簡單看看 IP 數據報的基本格式,並在最后討論一下路由器的選擇算法,看看一個 IP 數據報是如何被路由器給轉發出去的。
關於其中的各個字段或選項是如何被使用的,我們這里暫時先不做討論,強行解釋並適合大家理解,等到具體分析報文分發與解析時會容易理解很多。
路由器
路由器是網絡層的一個核心設備,它完成了從「目的 IP 地址」到「目的 IP 所在的子網絡」的完整路徑轉發過程。它的內部結構如下:
每個端口都直接連接了一台設備,而其中的『路由選擇處理器』則負責解析一個輸入端口進來的數據應該被推出到哪個輸出端口中去。
所以,你應該也發現了,整個路由器的核心應該是這個『路由選擇處理器』,也就是驅動這個『路由選擇處理器』工作的算法,我們稱之為『路由選擇算法』。算法本質上就是解決,一個數據報輸入進路由器內存,該從哪個輸出口轉發出去的問題。
一個好的 『路由選擇算法』不僅僅應該解決如何到達目的地的問題,還應該考慮如何最快的到達目的地,即能夠判斷並選擇性的繞過擁塞的網絡路徑。
整個路由選擇算法分為兩大類,全局式路由選擇算法和分散式路由選擇算法。前者的一個最典型的實現就是『鏈路狀態路由選擇算法』,后者的一個最典型的實現就是『距離向量算法』。
這兩者算法的理論原理這里不再和大家一起探討了,我們着重看看因特網中是如何基於這兩種算法實現的路由選擇。
首先,整個因特網是一個很龐大且復雜的系統,所以整體上被划分為一個一個的自治系統(AS),在每一個 AS 中都運行着同樣的路由算法,自治系統之間使用 BGP 協議交換信息。
整個因特網大致就是這樣的一個個自治系統互聯構成的,而自治系統內部的所有路由器都運行着同樣的路由選擇算法,基於距離向量的『RIP 協議』或基於鏈路狀態的『OSPF 協議』。
至於為什么要拆分自治系統,等我們介紹完這個 RIP 或者 OSPF,你就明白了。
RIP 協議的算法是這樣的:
簡單的一個自治系統,我們以此為例看看整個 RIP 協議是如何工作的。
首先最開始,路由器 A 的轉發表肯定是這樣的:
----------------------------
目的子網 下一跳路由 跳數
x B 1
q E 1
----------------------------
其他路由器也是類似的,第一步都建立起與自己直接相連鄰居的連接。
第二步是一個不斷進行的過程,相鄰的路由器之間每隔 30 秒就相互交換信息,告知對方自己的轉發表內容。
所以經過一次交換之后,路由器 A 將收到來自 B 和 E 的轉發表信息,於是路由轉發表更新如下:
----------------------------
目的子網 下一跳路由 跳數
x B 1
q E 1
y B 2
p E 2
----------------------------
但是這里有一個細節,子網絡 y 是可以通過 A - B - y 到達的,但同時也可以通過 A - E - C - y 到達。你也許已經猜到了,路由器當然會選擇最短路徑的一條來更新自己的轉發表。
所以,這個距離向量的算法本質上就是通過相互之間不斷的交換信息以保證某個自治系統內,所有的路由器都知道某個目的子網的最短路徑。
OSPF 的實現是這樣的:
我們同樣以上面的例子進行解釋:
OSPF 是基於鏈路狀態路由選擇算法進行實現的,所以它也是一個全局性路由選擇算法,算法運行一次即可完成全網的路由信息更新。
而 OSPF 本質上就是一個迪傑斯特拉求最短路徑問題,它通過不斷的迭代與計算更新整個路由轉發表。假設現在我們的路由器 A 運行 OSPF 協議:
第一次迭代完成后,它得到與 B、E 兩台路由器相關的子網絡的路徑計算。
第二次以 B 或者 E 為起點重新運行算法,這里我們假設以 B 為起點運行了算法,那么與 C 相關的子網絡的路徑也被更新進 A 的路由轉發表。
第三次以 C 為起點同樣的運行算法,得到和 D 相關的子網絡路徑更新。
由於 D 作為末端路由,並沒有直接相連的其他路由,所以算法不再繼續,回到 E。
第四次,以 E 作為原點,運行算法,得到了 C 相關子網絡的路徑,如果有更短的路徑,將更新 A 的轉發表以最優路徑。
那么,待整個算法運行結束,一個自治系統中的所有路由器幾乎全部遍歷,但是卻不同於 RIP,OSPF 相對而言收斂快,可以迅速完成任務,而 RIP 則需要不斷的交換信息以達到需求,往往會陷入一個長周期。
當然了,OSPF 需要較強的 CPU 計算能力和更多的內存存儲空間。所以總的而言,他們都廣泛應用於整個因特網之中,RIP 應用在較為底層的 ISP 上,而 OSPF 則運行在較為高級的 ISP 中。
至此,整個網絡層的基本內容也介紹完了,總結一下,網絡層的核心任務就是負責轉發分組,而如何將分組轉發到目的主機的網絡中呢,牽扯出 IP 協議,通過 IP 地址與子網掩碼划分子網絡,而路由器執行路由選擇算法得知目的子網絡的完整路由路徑並進行分發。
鏈路層
網絡層解決的是,分組轉發的目的網絡,也就是轉發給目的網絡的網關路由,而鏈路層解決的是,將分組廣播給個人,也即目的主機。
網絡層的 IP 數據包會在鏈路層被封裝成『以太網幀』,它的基本結構是這樣的:
前導碼用於同步時鍾,按照我的理解就是區分一個一個的幀,源和目的地址指的是『Mac 地址』,也稱作物理地址。
『Mac 地址』是硬件級別的主機唯一標識,由生產廠家唯一確定。類似這樣:
34-E6-AD-17-A5-6B
全球任意一台主機的 Mac 地址都是不同的,它不像 IP 地址可以在別人不用的時候共享。
下面我們要講一個協議,它完成了主機 IP 地址到 Mac 地址的轉換,他就是 ARP 地址解析協議。
ARP 協議其實有點類似於我們之間在應用層介紹的 DNS 協議,輸入一個域名 地址,輸出一個 IP 地址,而 ARP 而言,輸入一個 IP 地址,輸出一個 Mac 地址。
網絡中的每台主機,包括路由器,都內置的 ARP 模塊和 ARP 表。當一份數據報到達鏈路層時,首先要做的就是以該數據報的目的 IP 作為輸入,先查詢自己主機的 ARP 模塊,如果能夠得到該 IP 的目的主機 Mac 地址,那么封裝一個以太網幀交給物理層發送出去就好。
而如果本機的 ARP 表中並沒有存儲目的 IP 主機的 Mac 地址,那么就需要向同網絡中的其他主機進行查詢。
發送方會構建一個特殊的 ARP 分組,源 Mac 地址為發送方的 Mac 地址,目的 Mac 地址為廣播地址:255.255.255.255,以及源和目的 IP 地址,本質上就是一個特殊的以太網幀。
於是該網絡下的所有主機都將收到這個 ARP 分組,那么他們要做的就是拆開 IP 地址比對是否和自己的 IP 地址相同,如果是則響應一個 ARP 分組,告訴發送方自己的 Mac 地址。
如果不是自己,則還會檢查自己的 ARP 模塊,看看是否能提供幫助。
最終,發送方會得到想要的目的 Mac 地址並更新自己的 ARP 表,然后封裝一個正常的以太網幀發送出去。
由於以太網采取的是『廣播』方式,所以同一子網絡中任意一台主機發送報文,所有的其余主機都會收到,但是它們會匹配目的 Mac 地址是否是自己,不是則丟棄,這一點很重要。
好了,那么到此為止我們也簡單介紹了鏈路層的相關內容,關於物理層,其實沒什么介紹的,就是 0、1 的電信號傳輸。
關於整個 OSI 五層模型,我們從上至下也已經完成了學習,下一篇將完整的看看 「www.baidu.com」之后,整個計算機網絡發生的故事,其實有點標題黨了,最后一篇才介紹完整的 HTTP 請求過程,見諒!
文章中的所有代碼、圖片、文件都雲存儲在我的 GitHub 上:
(https://github.com/SingleYam/overview_java)
歡迎關注微信公眾號:撲在代碼上的高爾基,所有文章都將同步在公眾號上。