電腦A和他的女朋友電腦B坐在一塊聊天,這就是網絡。IO、中斷、緩衝區這都不是研究網絡時該關心的事

你是一臺電腦,你的名字叫 A

很久很久之前,你不與任何其他電腦相連接,孤苦伶仃。

直到有一天,你希望與另一臺電腦 B 建立通信,於是你們各開了一個網口,用一根網線連接了起來。

用一根網線連接起來怎麼就能"通信"了呢?我可以給你講 IO、講中斷、講緩衝區,但這不是研究網絡時該關心的問題。

如果你糾結,要麼去研究一下操作系統是如何處理網絡 IO 的,要麼去研究一下包是如何被網卡轉換成電信號發送出去的,要麼就僅僅把它當做電腦裏有個小人在開槍吧~

反正,你們就是連起來了,並且可以通信。

 

第一層

 

有一天,一個新夥伴 C 加入了,但聰明的你們很快發現,可以每個人開兩個網口,用一共三根網線,彼此相連。

隨着越來越多的人加入,你發現身上開的網口實在太多了,而且網線密密麻麻,混亂不堪。(而實際上一臺電腦根本開不了這麼多網口,所以這種連線只在理論上可行,所以連不上的我就用紅色虛線表示了,就是這麼嚴謹哈哈~)

於是你們發明了一箇中間設備,你們將網線都插到這個設備上,由這個設備做轉發,就可以彼此之間通信了,本質上和原來一樣,只不過網口的數量和網線的數量減少了,不再那麼混亂。

你給它取名叫集線器,它僅僅是無腦將電信號轉發到所有出口(廣播),不做任何處理,你覺得它是沒有智商的,因此把人家定性在了物理層

 

由於轉發到了所有出口,那 BCDE 四臺機器怎麼知道數據包是不是發給自己的呢?

首先,你要給所有的連接到交換機的設備,都起個名字。原來你們叫 ABCD,但現在需要一個更專業的,全局唯一的名字作爲標識,你把這個更高端的名字稱爲 MAC 地址

你的 MAC 地址是 aa-aa-aa-aa-aa-aa,你的夥伴 b 的 MAC 地址是 bb-bb-bb-bb-bb-bb,以此類推,不重複就好。

這樣,A 在發送數據包給 B 時,只要在頭部拼接一個這樣結構的數據,就可以了。

B 在收到數據包後,根據頭部的目標 MAC 地址信息,判斷這個數據包的確是發給自己的,於是便收下

其他的 CDE 收到數據包後,根據頭部的目標 MAC 地址信息,判斷這個數據包並不是發給自己的,於是便丟棄

雖然集線器使整個佈局乾淨不少,但原來我只要發給電腦 B 的消息,現在卻要發給連接到集線器中的所有電腦,這樣既不安全,又不節省網絡資源。

 

第二層

 

如果把這個集線器弄得更智能一些,只發給目標 MAC 地址指向的那臺電腦,就好了。

雖然只比集線器多了這一點點區別,但看起來似乎有智能了,你把這東西叫做交換機。也正因爲這一點點智能,你把它放在了另一個層級,數據鏈路層

 

如上圖所示,你是這樣設計的。

交換機內部維護一張 MAC 地址表,記錄着每一個 MAC 地址的設備,連接在其哪一個端口上。

MAC 地址 端口
bb-bb-bb-bb-bb-bb 1
cc-cc-cc-cc-cc-cc 3
aa-aa-aa-aa-aa-aa 4
dd-dd-dd-dd-dd-dd 5

假如你仍然要發給 B 一個數據包,構造瞭如下的數據結構從網口出去。

到達交換機時,交換機內部通過自己維護的 MAC 地址表,發現目標機器 B 的 MAC 地址 bb-bb-bb-bb-bb-bb 映射到了端口 1 上,於是把數據從 1 號端口發給了 B,完事~

你給這個通過這樣傳輸方式而組成的小範圍的網絡,叫做以太網

當然最開始的時候,MAC 地址表是空的,是怎麼逐步建立起來的呢?

假如在 MAC 地址表爲空是,你給 B 發送瞭如下數據

由於這個包從端口 4 進入的交換機,所以此時交換機就可以在 MAC地址表記錄第一條數據:

MAC:aa-aa-aa-aa-aa-aa-aa
端口:4

交換機看目標 MAC 地址(bb-bb-bb-bb-bb-bb)在地址表中並沒有映射關係,於是將此包發給了所有端口,也即發給了所有機器。

之後,只有機器 B 收到了確實是發給自己的包,於是做出了響應,響應數據從端口 1 進入交換機,於是交換機此時在地址表中更新了第二條數據:

MAC:bb-bb-bb-bb-bb-bb
端口:1

過程如下

經過該網絡中的機器不斷地通信,交換機最終將 MAC 地址表建立完畢~

隨着機器數量越多,交換機的端口也不夠了,但聰明的你發現,只要將多個交換機連接起來,這個問題就輕而易舉搞定~

你完全不需要設計額外的東西,只需要按照之前的設計和規矩來,按照上述的接線方式即可完成所有電腦的互聯,所以交換機設計的這種規則,真的很巧妙。你想想看爲什麼(比如 A 要發數據給 F)。

但是你要注意,上面那根紅色的線,最終在 MAC 地址表中可不是一條記錄呀,而是要把 EFGH 這四臺機器與該端口(端口6)的映射全部記錄在表中。

最終,兩個交換機將分別記錄 A ~ H 所有機器的映射記錄

左邊的交換機

MAC 地址 端口
bb-bb-bb-bb-bb-bb 1
cc-cc-cc-cc-cc-cc 3
aa-aa-aa-aa-aa-aa 4
dd-dd-dd-dd-dd-dd 5
ee-ee-ee-ee-ee-ee 6
ff-ff-ff-ff-ff-ff 6
gg-gg-gg-gg-gg-gg 6
hh-hh-hh-hh-hh-hh 6

右邊的交換機

MAC 地址 端口
bb-bb-bb-bb-bb-bb 1
cc-cc-cc-cc-cc-cc 1
aa-aa-aa-aa-aa-aa 1
dd-dd-dd-dd-dd-dd 1
ee-ee-ee-ee-ee-ee 2
ff-ff-ff-ff-ff-ff 3
gg-gg-gg-gg-gg-gg 4
hh-hh-hh-hh-hh-hh 6

這在只有 8 臺電腦的時候還好,甚至在只有幾百臺電腦的時候,都還好,所以這種交換機的設計方式,已經足足支撐一陣子了。

但很遺憾,人是貪婪的動物,很快,電腦的數量就發展到幾千、幾萬、幾十萬。

 

第三層交換機已經無法記錄如此龐大的映射關係了。

此時你動了歪腦筋,你發現了問題的根本在於,連出去的那根紅色的網線,後面不知道有多少個設備不斷地連接進來,從而使得地址表越來越大。

那我可不可以讓那根紅色的網線,接入一個新的設備,這個設備就跟電腦一樣有自己獨立的 MAC 地址,而且同時還能幫我把數據包做一次轉發呢?

這個設備就是路由器,它的功能就是,作爲一臺獨立的擁有 MAC 地址的設備,並且可以幫我把數據包做一次轉發你把它定在了網絡層。

注意,路由器的每一個端口,都有獨立的 MAC 地址

好了,現在交換機的 MAC 地址表中,只需要多出一條 MAC 地址 ABAB 與其端口的映射關係,就可以成功把數據包轉交給路由器了,這條搞定。

那如何做到,把發送給 C 和 D,甚至是把發送給 DEFGH.... 的數據包,統統先發送給路由器呢?

不難想到這樣一個點子,假如電腦 C 和 D 的 MAC 地址擁有共同的前綴,比如分別是

C 的 MAC 地址:FFFF-FFFF-CCCC
D 的 MAC 地址:FFFF-FFFF-DDDD

那我們就可以說,將目標 MAC 地址爲 FFFF-FFFF-?開頭的,統統先發送給路由器。

這樣是否可行呢?答案是否定的。

我們先從現實中 MAC 地址的結構入手,MAC地址也叫物理地址、硬件地址,長度爲 48 位,一般這樣來表示

00-16-EA-AE-3C-40

它是由網絡設備製造商生產時燒錄在網卡的EPROM(一種閃存芯片,通常可以通過程序擦寫)。其中前 24 位(00-16-EA)代表網絡硬件製造商的編號,後 24 位(AE-3C-40)是該廠家自己分配的,一般表示系列號。只要不更改自己的 MAC 地址,MAC 地址在世界是唯一的。形象地說,MAC地址就如同身份證上的身份證號碼,具有唯一性。

那如果你希望向上面那樣表示將目標 MAC 地址爲 FFFF-FFFF-?開頭的,統一從路由器出去發給某一羣設備(後面會提到這其實是子網的概念),那你就需要要求某一子網下統統買一個廠商製造的設備,要麼你就需要要求廠商在生產網絡設備燒錄 MAC 地址時,提前按照你規劃好的子網結構來定 MAC 地址,並且日後這個網絡的結構都不能輕易改變。

也許乾巴巴的文字看起來有寫枯燥,如果單看文字不是很容易消化的話,可以進羣973961276來跟大家一起交流學習,羣裏也有許多視頻資料和技術大牛,配合文章一起理解應該會讓你有不錯的收穫。

推薦一個不錯的c/c++ 初學者課程,這個跟以往所見到的只會空談理論的有所不同,這個課程是從六個可以寫在簡歷上的企業級項目入手帶領大家學習c/c++,正在學習的朋友可以瞭解一下。

這顯然是不現實的。

於是你發明了一個新的地址,給每一臺機器一個 32 位的編號,如:

11000000101010000000000000000001

你覺得有些不清晰,於是把它分成四個部分,中間用點相連。

11000000.10101000.00000000.00000001

你還覺得不清晰,於是把它轉換成 10 進制。

192.168.0.1

最後你給了這個地址一個響亮的名字,IP 地址。現在每一臺電腦,同時有自己的 MAC 地址,又有自己的 IP 地址,只不過 IP 地址是軟件層面上的,可以隨時修改,MAC 地址一般是無法修改的。

這樣一個可以隨時修改的 IP 地址,就可以根據你規劃的網絡拓撲結構,來調整了。

如上圖所示,假如我想要發送數據包給 ABCD 其中一臺設備,不論哪一臺,我都可以這樣描述,"將 IP 地址爲 192.168.0 開頭的全部發送給到路由器,之後再怎麼轉發,交給它!",巧妙吧。

那交給路由器之後,路由器又是怎麼把數據包準確轉發給指定設備的呢?

別急我們慢慢來。

我們先給上面的組網方式中的每一臺設備,加上自己的 IP 地址

 

現在兩個設備之間傳輸,除了加上數據鏈路層的頭部之外,還要再增加一個網絡層的頭部。

假如 A 給 B 發送數據,由於它們直接連着交換機,所以 A 直接發出如下數據包即可,其實網絡層沒有體現出作用。

但假如 A 給 C 發送數據,A 就需要先轉交給路由器,然後再由路由器轉交給 C。由於最底層的傳輸仍然需要依賴以太網,所以數據包是分成兩段的。

A ~ 路由器這段的包如下:

路由器到 C 這段的包如下:

好了,上面說的兩種情況(A->B,A->C),相信細心的讀者應該會有不少疑問,下面我們一個個來展開。

A 給 C 發數據包,怎麼知道是否要通過路由器轉發呢?

答案:子網

如果源 IP 與目的 IP 處於一個子網,直接將包通過交換機發出去。

如果源 IP 與目的 IP 不處於一個子網,就交給路由器去處理。

好,那現在只需要解決,什麼叫處於一個子網就好了。

  • 192.168.0.1 和 192.168.0.2 處於同一個子網

  • 192.168.0.1 和 192.168.1.1 處於不同子網

這兩個是我們人爲規定的,即我們想表示,對於 192.168.0.1 來說:

192.168.0.xxx 開頭的,就算是在一個子網,否則就是在不同的子網。

那對於計算機來說,怎麼表達這個意思呢?於是人們發明了子網掩碼的概念

假如某臺機器的子網掩碼定爲 255.255.255.0

這表示,將源 IP 與目的 IP 分別同這個子網掩碼進行與運算,相等則是在一個子網,不相等就是在不同子網,就這麼簡單。

比如

  • A電腦:192.168.0.1 & 255.255.255.0 = 192.168.0.0

  • B電腦:192.168.0.2 & 255.255.255.0 = 192.168.0.0

  • C電腦:192.168.1.1 & 255.255.255.0 = 192.168.1.0

  • D電腦:192.168.1.2 & 255.255.255.0 = 192.168.1.0

那麼 A 與 B 在同一個子網,C 與 D 在同一個子網,但是 A 與 C 就不在同一個子網,與 D 也不在同一個子網,以此類推。

所以如果 A 給 C 發消息,A 和 C 的 IP 地址分別 & A 機器配置的子網掩碼,發現不相等,則 A 認爲 C 和自己不在同一個子網,於是把包發給路由器,就不管了,之後怎麼轉發,A 不關心

A 如何知道,哪個設備是路由器?

答案:在 A 上要設置默認網關

上一步 A 通過是否與 C 在同一個子網內,判斷出自己應該把包發給路由器,那路由器的 IP 是多少呢?

其實說發給路由器不準確,應該說 A 會把包發給默認網關

對 A 來說,A 只能直接把包發給同處於一個子網下的某個 IP 上,所以發給路由器還是發給某個電腦,對 A 來說也不關心,只要這個設備有個 IP 地址就行。

所以默認網關,就是 A 在自己電腦裏配置的一個 IP 地址,以便在發給不同子網的機器時,發給這個 IP 地址。

僅此而已!

路由器如何知道C在哪裏?

答案:路由表

現在 A 要給 C 發數據包,已經可以成功發到路由器這裏了,最後一個問題就是,路由器怎麼知道,收到的這個數據包,該從自己的哪個端口出去,才能直接(或間接)地最終到達目的地 C 呢。

路由器收到的數據包有目的 IP 也就是 C 的 IP 地址,需要轉化成從自己的哪個端口出去,很容易想到,應該有個表,就像 MAC 地址表一樣。

這個表就叫路由表

至於這個路由表是怎麼出來的,有很多路由算法,本文不展開,因爲我也不會哈哈~

不同於 MAC 地址表的是,路由表並不是一對一這種明確關係,我們下面看一個路由表的結構。

目的地址 子網掩碼 下一跳 端口
192.168.0.0 255.255.255.0   0
192.168.0.254 255.255.255.255   0
192.168.1.0 255.255.255.0   1
192.168.1.254 255.255.255.255   1

我們學習一種新的表示方法,由於子網掩碼其實就表示前多少位表示子網的網段,所以如 192.168.0.0(255.255.255.0) 也可以簡寫爲 192.168.0.0/24

目的地址 下一跳 端口
192.168.0.0/24   0
192.168.0.254/32   0
192.168.1.0/24   1
192.168.1.254/32   1

這就很好理解了,路由表就表示,192.168.0.xxx 這個子網下的,都轉發到 0 號端口,192.168.1.xxx 這個子網下的,都轉發到 1 號端口。下一跳列還沒有值,我們先不管

配合着結構圖來看(這裏把子網掩碼和默認網關都補齊了)

 

剛纔說的都是 IP 層,但發送數據包的數據鏈路層需要知道 MAC 地址,可是我只知道 IP 地址該怎麼辦呢?

答案:arp

假如你(A)此時不知道你同伴 B 的 MAC 地址(現實中就是不知道的,剛剛我們只是假設已知),你只知道它的 IP 地址,你該怎麼把數據包準確傳給 B 呢?

答案很簡單,在網絡層,我需要把 IP 地址對應的 MAC 地址找到,也就是通過某種方式,找到 192.168.0.2 對應的 MAC 地址 BBBB

這種方式就是 arp 協議,同時電腦 A 和 B 裏面也會有一張 arp 緩存表,表中記錄着 IP 與 MAC 地址的對應關係。

IP 地址 MAC 地址
192.168.0.2 BBBB

一開始的時候這個表是空的,電腦 A 爲了知道電腦 B(192.168.0.2)的 MAC 地址,將會廣播一條 arp 請求,B 收到請求後,帶上自己的 MAC 地址給 A 一個響應。此時 A 便更新了自己的 arp 表。

這樣通過大家不斷廣播 arp 請求,最終所有電腦裏面都將 arp 緩存表更新完整。

總結一下

好了,總結一下,到目前爲止就幾條規則

從各個節點的視角來看

電腦視角

  • 首先我要知道我的 IP 以及對方的 IP

  • 通過子網掩碼判斷我們是否在同一個子網

  • 在同一個子網就通過 arp 獲取對方 mac 地址直接扔出去

  • 不在同一個子網就通過 arp 獲取默認網關的 mac 地址直接扔出去

交換機視角:

  • 我收到的數據包必須有目標 MAC 地址

  • 通過 MAC 地址表查映射關係

  • 查到了就按照映射關係從我的指定端口發出去

  • 查不到就所有端口都發出去

路由器視角:

  • 我收到的數據包必須有目標 IP 地址

  • 通過路由表查映射關係

  • 查到了就按照映射關係從我的指定端口發出去(不在任何一個子網範圍,走其路由器的默認網關也是查到了)

  • 查不到則返回一個路由不可達的數據包

如果你嗅覺足夠敏銳,你應該可以感受到下面這句話:

網絡層(IP協議)本身沒有傳輸包的功能,包的實際傳輸是委託給數據鏈路層(以太網中的交換機)來實現的。

涉及到的三張表分別是

  • 交換機中有 MAC 地址表用於映射 MAC 地址和它的端口

  • 路由器中有路由表用於映射 IP 地址(段)和它的端口

  • 電腦和路由器中都有 arp 緩存表用於緩存 IP 和 MAC 地址的映射關係

這三張表是怎麼來的

  • MAC 地址表是通過以太網內各節點之間不斷通過交換機通信,不斷完善起來的。

  • 路由表是各種路由算法 + 人工配置逐步完善起來的。

  • arp 緩存表是不斷通過 arp 協議的請求逐步完善起來的。

知道了以上這些,目前網絡上兩個節點是如何發送數據包的這個過程,就完全可以解釋通了!

那接下來我們就放上本章 最後一個 網絡拓撲圖吧,請做好 戰鬥 準備!

這時路由器 1 連接了路由器 2,所以其路由表有了下一條地址這一個概念,所以它的路由表就變成了這個樣子。如果匹配到了有下一跳地址的一項,則需要再次匹配,找到其端口,並找到下一跳 IP 的 MAC 地址。

也就是說找來找去,最終必須能映射到一個端口號,然後從這個端口號把數據包發出去。

目的地址 下一跳 端口
192.168.0.0/24   0
192.168.0.254/32   0
192.168.1.0/24   1
192.168.1.254/32   1
192.168.2.0/24 192.168.100.5  
192.168.100.0/24   2
192.168.100.4/32   2

這時如果 A 給 F 發送一個數據包,能不能通呢?如果通的話整個過程是怎樣的呢?

思考一分鐘...

詳細過程動畫描述:

詳細過程文字描述:

1. 首先 A(192.168.0.1)通過子網掩碼(255.255.255.0)計算出自己與 F(192.168.2.2)並不在同一個子網內,於是決定發送給默認網關(192.168.0.254)

2. A 通過 ARP 找到 默認網關 192.168.0.254 的 MAC 地址。

3. A 將源 MAC 地址(AAAA)與網關 MAC 地址(ABAB)封裝在數據鏈路層頭部,又將源 IP 地址(192.168.0.1)和目的 IP 地址(192.168.2.2)(注意這裏千萬不要以爲填寫的是默認網關的 IP 地址,從始至終這個數據包的兩個 IP 地址都是不變的,只有 MAC 地址在不斷變化)封裝在網絡層頭部,然後發包

4. 交換機 1 收到數據包後,發現目標 MAC 地址是 ABAB,轉發給路由器1

5. 數據包來到了路由器 1,發現其目標 IP 地址是 192.168.2.2,查看其路由表,發現了下一跳的地址是 192.168.100.5

6. 所以此時路由器 1 需要做兩件事,第一件是再次匹配路由表,發現匹配到了端口爲 2,於是將其封裝到數據鏈路層,最後把包從 2 號口發出去。

7. 此時路由器 2 收到了數據包,看到其目的地址是 192.168.2.2,查詢其路由表,匹配到端口號爲 1,準備從 1 號口把數據包送出去。

8. 但此時路由器 2 需要知道 192.168.2.2 的 MAC 地址了,於是查看其 arp 緩存,找到其 MAC 地址爲 FFFF,將其封裝在數據鏈路層頭部,並從 1 號端口把包發出去。

9. 交換機 3 收到了數據包,發現目的 MAC 地址爲 FFFF,查詢其 MAC 地址表,發現應該從其 6 號端口出去,於是從 6 號端口把數據包發出去。

10. F 最終收到了數據包!並且發現目的 MAC 地址就是自己,於是收下了這個包

更詳細且精準的過程:

讀到這相信大家已經很累了,理解上述過程基本上網絡層以下的部分主流程就基本疏通了,如果你想要本過程更爲專業的過程描述,可以在公衆號 低併發編程 後臺回覆 網絡,獲得我模擬這個過程的 Cisco Packet Tracer 源文件。

每一步包的傳輸都會有各層的原始數據,以及專業的過程描述

 

同時在此基礎之上你也可以設計自己的網絡拓撲結構,進行各種實驗,來加深網絡傳輸過程的理解。

後記

至此,經過物理層、數據鏈路層、網絡層這前三層的協議,以及根據這些協議設計的各種網絡設備(網線、集線器、交換機、路由器),理論上只要擁有對方的 IP 地址,就已經將地球上任意位置的兩個節點連通了。

本文經過了很多次的修改,刪減了不少影響主流程的內容,就是爲了讓讀者能抓住網絡傳輸前三層的真正核心思想。同時網絡相關的知識也是多且雜,我也還有很多搞不清楚的地方,非常歡迎大家與我交流,共同進步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章