本系列即將結束,最後一章將仔細討論網路系統,這是面試中經常被問及的一個知識點,也是工作中常遇到的一個系統知識點。那麼為什麼我們需要網路系統呢?我們之前提到過,程序間通訊有許多方法,其中一種是通過通訊端(socket)進行跨網路通訊。這意味著我們不再僅限於內部系統呼叫,而是需要與其他人進行溝通,這也是網際網路的本質。然而,如果我們不能使用共同的語言進行溝通,比如你說中文,對方說鳥語,那麼你們將無法有效地交流。因此,我們需要一個統一的語言,也就是網路系統,它通過一系列協定確保雙方能夠正常有效地進行溝通。這種約定好的格式就是網路協定(Networking Protocol)。接下來,我們將詳細討論網路系統的相關內容。
首先,我將簡單地解釋一下,然後再進行詳細說明。為什麼要分層?其實,這與你在編寫Java程式碼時為什麼要使用責任鏈設計模式是一樣的。每一層只負責自己的任務,如果符合我們所需的邏輯,就繼續往下一層推進,直到問題得到解決。難道不分層也可以嗎?實際上不行,因為我們的設計模式只存在於程式碼層面,並不能僅憑一些混亂的程式碼和一堆if-else語句就解決問題,畢竟我們還需要硬體的支援。
接下來,讓我們構建一個相對簡單的場景,並在後面的內容中基於這個場景進行講解。
假設我們有三臺機器,分別是Linux伺服器A、Linux伺服器B,它們位於不同的網段,並通過中間的Linux伺服器作為路由器進行轉發。
說到網路協定,我們還需要簡要介紹一下兩種網路協定模型。一種是OSI的標準七層模型,它包括物理層、資料鏈路層、網路層、傳輸層、對談層、表示層和應用層。另一種是業界標準的TCP/IP模型,它包括網路介面層、網路層、傳輸層和應用層。這兩種模型的對應關係如下圖所示:
為什麼網路要分層呢?這是因為網路環境過於複雜,不是一個能夠集中控制的體系。全球範圍內有數以億計的伺服器和裝置,它們各自擁有自己的體系結構和功能。然而,通過將網路劃分為多個層次和組合,使用統一的網路協定棧,可以滿足不同伺服器和裝置之間的通訊需求。
我們這裡簡單介紹一下網路協定的幾個層次。讓我們從第三層開始,也就是網路層,因為這一層包含了我們熟悉的IP地址。因此,這一層也被稱為IP層。
我們通常看到的IP地址的格式是這樣的:192.168.1.100/24。斜槓前面是IP地址,這個地址被點分隔為四個部分,每個部分由8位元二進位制數位組成,總共是32位元。斜線後面的24表示,在這32位元中,前24位元是網路號,後8位元是主機號。
為什麼要這樣劃分呢?我們可以想象一下,雖然全世界都組成了一個大的網際網路,你可以存取美國的網站,但這個網路並不是一個整體。你所在的小區有一個網路,你所在的公司也有一個網路,聯通、移動、電信等運營商也都有各自的網路。因此,整個大網路被劃分為許多小的網路。
那麼如何區分這些網路呢?這就是網路號的概念。一個網路中會有多個裝置,這些裝置的網路號相同,但主機號不同。你可以觀察一下你家裡的手機、電視和電腦,它們的主機號是不同的,但前面幾位的網路號是相同的,而且它們都連線到同一個閘道器。
連線到網路上的每個裝置都至少有一個IP地址,用於定位該裝置。無論是旁邊同學的電腦還是遙遠的電商網站,都可以通過IP地址進行定位。因此,IP地址類似於網際網路上的郵寄地址,具有全域性定位功能。但要記住,你的IP地址並不是永恆不變的。即使你使用手機流量,當你換一個地方時,基站也會改變,因此你的IP地址也會改變。所以現在你明白為什麼可以定位到你的裝置了吧。
即使你要存取美國的某個地址,也可以從你身邊的網路出發,通過打聽和詢問的過程,經過多個網路,最終發現中國的網路防火牆阻止了存取。開個玩笑,實際上只要是國內的地址,最終也可以到達目標地址,就像快遞員送包裹一樣。打聽和詢問的協定也在第三層,稱為路由協定(Routing protocol),它負責將網路包從一個網路轉發給另一個網路的裝置,這些裝置被稱為路由器。
總而言之,第三層的主要功能是將網路包從一個起始IP地址,沿著路由協定指定的路徑,通過多個網路,經過多個路由器的轉發,到達目標IP地址。
從第三層開始往下看,第二層是資料鏈路層,也稱MAC層。MAC是每個網路卡都有的唯一硬體地址(不絕對唯一,相對大概率唯一即可),雖然這個地址沒有全域性定位功能。
可以將MAC地址類比為外賣小哥送外賣時的手機尾號。儘管手機尾號無法準確找到你家的位置,但它在本地具有定位功能,主要通過「吼」的方式實現。當外賣小哥到達你所在樓層時,會大聲喊出:「尾號xxxx的,你的外賣到了!」MAC地址的定位功能僅限於同一網路內的IP地址之間,可以通過MAC地址定位和通訊。要通過IP地址獲取MAC地址,需要使用ARP協定,在本地傳送廣播包,也就是「吼」,以獲取MAC地址。實際上,ARP協定有快取功能,你可以使用arp -a命令檢視你的Windows機器的快取地址。
由於同一網路內的機器數量有限,通過MAC地址的好處在於簡單。只要匹配到MAC地址,就接收該封包;無法匹配到MAC地址,就不接收。沒有像路由協定那樣複雜的協定。當然,MAC地址的作用範圍僅限於本地網路,因此一旦跨網路通訊,儘管IP地址保持不變,但是MAC地址在經過每個路由器時都會更換一次。
讓我們再看一下前面的圖。伺服器A向伺服器B傳送網路封包,源IP地址始終是192.168.1.100,目標IP地址始終是192.168.2.100。但在網路1中,源MAC地址是MAC1,目標MAC地址是路由器的MAC2。路由器轉發後,源MAC地址變為路由器的MAC3,目標MAC地址變為MAC4。
所以在網路的第二層,主要負責處理本地網路中伺服器之間的定位和通訊機制,也就是封包在本地網路內的傳輸和交換。需要注意的是,這個機制僅限於本地網路內部的通訊。
我們再往下看,網路的第一層是物理層,這一層主要涉及物理裝置。例如,與電腦連線的網線以及我們能夠連線上的WiFi都屬於物理層的裝置。物理層負責將資料轉換為電訊號或者無線訊號,在網路中進行傳輸。
讓我們進一步深入瞭解網路分層的細節。從第三層開始,第四層就是傳輸層,其中包括兩個著名的協定,即TCP和UDP。尤其是TCP,在IP層的程式碼邏輯中,僅負責將資料從一個IP地址傳送到另一個IP地址,而不關心丟包、亂序、重傳、擁塞等問題。這些問題的處理邏輯被寫在傳輸層的TCP協定中。
我們經常說的TCP三次握手、四次揮手等,正是因為底層的幾個協定都不負責傳輸的可靠性。網路包可能會丟失,但是TCP層通過各種編號和重傳機制,使本來不可靠的網路看起來變得可靠。因此,哪有什麼應用層歲月靜好,只不過 TCP 層幫你負重前行。
傳輸層再往上一層是應用層,這一層包括我們常見的HTTP、FTP和Java Servlet等。二層到四層的處理都在Linux核心中進行,而應用層如瀏覽器、Nginx和Tomcat則執行在使用者態。核心對網路包的處理並不區分應用。
從第四層傳輸層往上,我們需要引入埠的概念。因為每個應用程式都需要佔用一個埠來區分哪些網路包是發給它的。不同的程式需要監聽不同的埠,例如Nginx可以監聽80和443埠,Tomcat監聽8080埠,Nacos監聽8848埠等。
應用層和傳輸層之間的通訊機制實際上是通過核心中的系統呼叫來完成的,即socket。因此,有人會問Socket屬於哪一層,實際上它不屬於任何一層,它只是一個由作業系統提供的系統呼叫介面。它屬於作業系統的概念,而不是網路協定分層的概念。只是作業系統選擇以一種模式實現網路協定處理,即將二到四層的處理程式碼放在核心中,而七層的處理程式碼由應用自己完成。這兩者之間需要跨越核心態和使用者態之間的通訊,所以需要一個系統呼叫來完成這個銜接,這就是Socket。
網路系統是面試和工作中常被問及的一個知識點。網路分層的核心思想是將網路劃分為多個層次和組合,使用統一的網路協定棧,滿足不同裝置之間的通訊需求。網路的第三層是網路層,負責將網路包從一個起始IP地址通過多個網路、經過多個路由器的轉發,到達目標IP地址。第二層是資料鏈路層,負責本地網路內伺服器之間的定位和通訊機制。第一層是物理層,負責將資料轉換為電訊號或無線訊號,在網路中進行傳輸。從第三層開始往上,第四層是傳輸層,包括TCP和UDP協定,處理網路傳輸的可靠性。第五層是應用層,包括HTTP、FTP和Java Servlet等。應用層和傳輸層之間的通訊通過系統呼叫介面socket完成。