/ 發送數據包 /
我們前面已經了解到為什么網絡需要分層,每一層都有自己的職責。在發送數據包的過程中,這些層扮演著不同的角色。它們的主要任務是將數據包進行層層封裝后發送,并在接收端逐層解封裝。
就像下面的示意圖所展示的那樣,在部署在 linux 服務器 B 上的服務端 Nginx 和 Tomcat 通過 Socket 監聽著 80 和 8080 端口。這時,內核的數據結構(包括七層網絡協議等)就會記錄下這些信息。當有數據包發送到這兩個端口時,內核就會將這些數據包轉發給相應的進程。
在 Linux 服務器 A 上的客戶端,如果打開一個 Edge 并連接到 Nginx,同樣通過 Socket 連接,客戶端會被分配一個隨機端口 12345。同理,如果打開一個 Chrome 并連接到 Tomcat,同樣通過 Socket 連接,客戶端會被分配一個隨機端口 12346。這些客戶端的端口都是隨機分配的,因為作為客戶端,你只需要與其他人的服務器建立連接,而不需要一個固定的端口供所有人訪問,因為你不是服務器本身。
在客戶端上,當需要發送數據包時,通常會將請求封裝成一個 HTTP 協議,并通過調用 socket 發送到內核。然后在傳輸層(即 TCP 層),會創建用于維護連接、序列號和擁堵控制的數據結構。在封裝好的 HTTP 包的外層,還會再封裝一個剛包裝好的 TCP 頭,然后繼續傳輸到網絡 IP 層。
在網絡 IP 層,需要將目標 IP 和本機 IP 等信息封裝在 TCP 包的外層,即在 IP 頭中。隨后,數據包會繼續發送到數據鏈路層(即 mac 層),這時需要將本機的 MAC 地址和目標 MAC 地址封裝在 IP 包的外層,即在 MAC 頭中。最后,數據包會被發送到硬件網卡,準備發送出去。需要注意的是目標主機的 IP 地址是用來確定數據包的目的地(也就是真實的目標服務器 IP),而目標主機的 MAC 地址是用來確定數據包在局域網中的具體物理地址(可以認為是網關的 MAC 地址,并不是目標服務器 MAC 地址)。
終于發送的數據包準備好了,現在我們來詳細講述一下數據包在傳輸過程中發生的一些不為人知的事情。
當數據包到達交換機層,也被稱為二層設備或 MAC 設備,因為它主要處理 MAC 層的操作。交換機不會改變數據包的 MAC 地址,而是會尋找目標 MAC 地址。就像圖上標識的那樣,交換機會檢查數據包中的目標 MAC 地址,并根據自己的 MAC 地址表找到相應的端口,然后將數據包轉發給對應的端口。如果交換機找不到目標 MAC 地址的對應端口,它會采取一種特殊的方式來解決問題,就像是在大聲喊叫一樣。交換機會發送一個廣播幀,向所有連接的設備詢問“這是誰的 MAC 地址?”這樣,如果目標設備在網絡上,它就會回復交換機,并告訴它自己的 MAC 地址。交換機將收到的回復信息更新到自己的 MAC 地址表中,以便將來能夠更快地找到目標設備。如果交換機還是找不到目標 MAC 地址,那你看看是不是斷網了吧,你可能已經脫離了互聯網。
當路由器接收到數據包后,它會開始解析數據包的 MAC 頭,并查看是否與自己的 MAC 地址匹配。如果匹配成功,路由器就會將數據包交給 IP 層進行處理。在 IP 層,路由器會根據數據包的 IP 頭中的信息,在路由表中查找下一跳的信息,以確定應該從哪個網絡接口發出去。在這個例子中,根據路由表的信息,數據包將會從右邊的網絡接口發出去。我們通常將路由器稱為三層設備,因為它主要處理到第三層(即網絡層)。實際上,路由器在轉發數據包時會修改數據包的源 MAC 地址和目標 MAC 地址。
當從路由器右側的網口發送出去的數據包到達網絡 2 的交換機時,它將經歷一次二層處理,并被轉發到交換機右側的網口。
最終,數據包將被轉發到 Linux 服務器 B。服務器 B 會檢查數據包的目標 MAC 地址是否與自身匹配,如果匹配,則將 MAC 頭部取下,并將數據包交給上一層。接下來,在 IP 層,服務器 B 會檢查數據包的目標 IP 地址是否與自己匹配,如果匹配,則將 IP 頭部取下,并將數據包交給上一層。在 TCP 層,服務器 B 會根據 TCP 頭部中的序列號等信息驗證數據包的有效性,并將數據包緩存起來,等待應用層讀取。
應用層通過 Socket 監聽特定端口,當讀取數據時,操作系統內核會根據 TCP 頭部中的端口號,將數據包發送給相應的應用程序進行處理。這樣應用程序就可以讀取并處理網絡包了。
在應用層中,我們需要解析 HTTP 頭和正文,這是由應用層來處理的。應用框架(如 Tomcat 等)通常會幫助我們解析和處理數據包(粘包問題等),因此我們不需要過多考慮網絡層面的細節。通過解析,應用層能夠得知客戶端的請求,例如購買商品或請求網頁。一旦應用層處理完 HTTP 請求,結果會被封裝為 HTTP 網絡包,通過 Socket 接口發送給內核。
接下來,內核會對數據包進行多層封裝,從物理網口發送出去,經過網絡 2 的交換機和 Linux 路由器,最終到達網絡 1。在網絡 1 上,數據包經過網絡 1 的交換機,再次經過 Linux 服務器 A 的層層解封裝,然后通過 Socket 接口根據客戶端的隨機端口號發送給客戶端應用程序,即瀏覽器。這樣,瀏覽器就能夠顯示一個絢麗多彩的頁面了。
需要注意的是,這個示例比較簡單,所以返回請求的路徑與發送路徑相同。但在實際情況中,返回請求的路徑不一定是原路返回,而是再次經過上述的網絡處理邏輯。這是因為網絡中的路由器會根據路由表選擇最佳路徑,以確保數據包能夠快速、高效地到達目標設備。
即使在這個相對簡單的網絡環境中,發送數據包的過程也是非常復雜的。
/ 總結 /
發送數據包是一個復雜的過程,涉及到多個層次的封裝和解封裝。不同層次的協議和設備在這個過程中扮演著不同的角色,確保數據包能夠快速、高效地到達目標設備。在發送數據包的過程中,數據包會經過多個網絡設備和路由器,每一步都需要進行相關的處理和解析。發送數據包的過程需要考慮到各個層次的處理和協議的兼容性,以確保數據包能夠正確地到達目標設備,并被相應的應用程序處理。這個過程中涉及到的細節非常復雜,需要各個層次的協議和設備之間的配合和交互,才能實現數據的傳輸和交換。