在這個場景中有兩個網絡,這兩個網絡通過一臺具有兩個以太網接口(F0/0,F0/1)的路由器連接在一起。路由器的這兩個端口和你自己電腦上的RJ-45型號的網卡端口是一樣的,都是內建在路由器中的。現在我們來看一看當位於網絡A的主機A想要和位於網絡B的主機B進行通信時都發生了什麼?
ICMP協議封裝如下:
ICMP報頭 | (主機A) Ping 1.1.1.5 |
IP協議封裝如下:
IP報頭 | ICMP報頭 | (主機A) Ping 1.1.1.5 |
經過IP協議封裝的數據包只是完成了TCP/IP協議簇網絡層上的封裝,接下來要完成的是數據鏈路層的封裝。在進行數據鏈路層的信息封裝之前主機A還需啓動IP路由進程來判斷目標主機B在本地網絡還是在遠程網絡。若主機B在本地網絡,說明主機B和主機A在同一個邏輯子網中,也就是同一個IP網段內。若主機B在遠程網絡則說明主機B與主機A不在同一個網段內,比如本例中,主機A位於網絡A而主機B位於網絡B。顯而易見,在本例的網絡場景中主機A會判斷出主機B位於遠程網絡。那麼問題是主機A是如何做出判斷的呢?
首先主機A將自己的IP地址和子網掩碼作“與運算”。所謂與運算就是無論是二進制的“0”和“1”相與還是二進制的“0”和“0”相與,得出的結果都爲“0”,而只有二進制“1”和“1”相與得出的結果爲“1”。比如本例中,主機A的IP地址爲192.168.0.5,將這個IP地址轉換爲二進制就是:11000000 10101000 00000000 00000101
主機A的子網掩碼爲255.255.255.0,將該掩碼轉換爲二進制就是:11111111 11111111 11111111 00000000 將主機A二進制形式的IP地址和子網掩碼作“與運算”的結果是: 11000000 10101000 00000000 00000000
爲了方便查看將這個“與運算”的結果再轉換爲點分十進制的數就是:192.168.0.0
這樣主機A就通過“與運算”完成了IP路由判斷的第一步。接下來的第二步是將目標主機(主機B)的IP地址與發送方(主機A)的子網掩碼作“與運算”,比如本例中,主機B的IP地址爲1.1.1.5,將這個IP地址轉換爲二進制就是:00000001 00000001 00000001 00000101
主機A的子網掩碼爲255.255.255.0將該掩碼轉換爲二進制就是:11111111 11111111 11111111 00000000 將以上兩組二進制的數進行“與運算”的結果是:00000001 00000001 00000001 00000000 將這個“與運算”的結果轉換爲點分十進制的數就是:1.1.1.0 這樣我們就得到了兩組“與運算”的結果,分別是:192.168.0.0和1.1.1.0
對於主機A來說,經過這樣一番“與運算”後,如果兩個“與運算”結果相同,則說明目標主機B和自己在同一個網絡內,即目標主機B在本地網絡。相反地,對於主機A來說,經過這樣一番“與運算”後,如果兩個“與運算”結果不同,則說明目標主機B和自己不在同一個網絡內,即目標主機B在遠程網絡。在本例中,很顯然目標主機B對於發送方(主機A)來說在遠程網絡——也就是在網絡B。
主機A通過以上與目標主機B略顯複雜的“與運算”後,完成了路由判斷的第一步——判斷出了目標主機B在遠程網絡。接下來主機A需要“思考”的是如何才能夠到達主機B所在的網絡?主機A首先會查詢自己的路由表,看在自己的路由表中能否找到去往目標網絡(網絡B)的路由條目。爲了方便大家理解,我將主機A的路由表輸出顯示如下:
C:\>route print
Active Routes:
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 192.168.0.1 192.168.0.5 10
127.0.0.0 255.0.0.0 127.0.0.1 127.0.0.1 1
192.168.0.0 255.255.255.0 192.168.0.5 192.168.0.5 10
192.168.0.5 255.255.255.255 127.0.0.1 127.0.0.1 10
192.168.0.255 255.255.255.255 192.168.0.5 192.168.0.5 10
224.0.0.0 240.0.0.0 192.168.0.5 192.168.0.5 10
255.255.255.255 255.255.255.255 192.168.0.5 192.168.0.5 1
Default Gateway: 192.168.0.1
從主機A路由表的輸出顯示中我們沒有找到與目標主機B所在的網絡相匹配的具體路由,也就是說主機A沒有到達1.1.1.0這個網絡的路由。但是我們注意到在該路由表的最後一行輸出的是: Default Gateway(默認/缺省網關): 192.168.0.1 路由表最後一行的輸出說明主機A在沒有找到能夠到達目標網絡的具體路由的情況下,會將發往目標網絡的數據包發送到默認/缺省網關(192.168.0.1),由這個默認/缺省網關再將該數據包轉發到目標網絡。
好了,現在主機A知道了默認網關(192.168.0.1)是自己的下一跳地址,主機A開始執行封裝。封裝信息如下:
目的MAC: 下一跳設備的MAC |
源MAC: 主機A的MAC地址 |
源IP: 192.168.0.5 |
目的IP: 1.1.1.5 |
ICMP報頭 |
(主機A) Ping 1.1.1.5 |
在以上所封裝的尋址信息當中,主機A唯一不知道的就是“下一跳設備的MAC地址”,這裏的“下一跳設備MAC地址”是指主機A的默認網關192.168.0.1的F0/0接口的MAC地址。這裏容易讓人產生一個困惑,主機A的目的IP地址是主機B,那麼爲什麼主機A封裝的鏈路層的目的MAC地址卻是路由器F0/0的MAC地址呢?原因是當初人們在設計數據鏈路層時主要考慮如何解決一條線路上相鄰兩端設備之間的通信。
從這個網絡場景中我們看到主機A和主機B從各自所處的物理位置上看並不屬於相鄰的兩臺設備(中間隔着一臺路由器)。既然主機B並不是主機A直接相鄰的設備,那麼主機A在數據鏈路層封裝的目的MAC地址當然就不可能是主機B了。主機A通過IP路由的流程判斷和查詢路由表知道要想到達主機B就必須將數據包發給路由器A的F0/0接口(F0/0接口也是主機A到達主機B必經的直接相鄰的接口),因此F0/0的MAC地址就成爲主機A在數據鏈路層封裝的目的MAC地址。在本例中假如主機A要給Server A發送數據而不是給主機B,那麼主機A在數據鏈路層封裝的目的MAC地址就是Server A的MAC地址,因爲Server A與主機A是彼此直接相鄰的設備。那麼對於主機A來說它是否知道路由器F0/0接口的MAC地址呢?主機A是不知道的。所以接下來主機A需要做的是如何才能找到F0/0接口的MAC地址以完成數據鏈路層的封裝成幀。首先主機A查看自己的ARP緩存表,每臺主機/電腦都有這個ARP緩存表,該緩存表記錄着與自己發生過通信的所有的直接相鄰設備或主機的硬件地址(MAC地址),ARP緩存表經過一段時間會自動刪除,比如Windows 的動態 ARP 緩存條目不超過 10 分鐘就會被刪除。如果主機A與路由器之前曾發生過通信,主機A自然能在ARP緩存表中找到路由器F0/0的硬件MAC地址,可是如果這是主機A與路由器的第一次通信,則主機A會向網絡A上發送發送ARP廣播請求數據包,該ARP請求包包含的關鍵信息如下:
發送方IP地址(192.168.0.5) | 發送方MAC地址(主機A MAC地址) |
目的IP地址(192.168.0.1) | 目的MAC地址(000000000000) |
以上ARP請求包中封裝的三項信息都是已知的,只有“目的MAC地址”這一信息是未知的(全“0”填充)。當該ARP請求包發送到網絡A上時,網絡A上的設備接收該ARP包並查看該ARP包內的具體封裝信息。因爲該ARP包中封裝的目的IP地址是192.168.0.1,所以只有具有192.168.0.1這個IP的接口或設備才應答該ARP查詢請求,應答者會將自己的硬件MAC地址封裝到這個ARP應答數據包中。這個ARP應答數據包(本例中由路由器F0/0接口發出ARP應答)封裝的關鍵信息如下:
發送方IP地址(192.168.0.1) | 發送方MAC地址(F0/0接口MAC地址) |
目的IP地址(192.168.0.5) | 目的MAC地址(主機A的MAC地址) |
主機A通過ARP協議解析出路由器F0/0接口的MAC地址從而完成了數據鏈路層的封裝。通過主機A這個解析過程大家可以看到主機A在第一次與默認網關通信時的確是費了一番周折,爲了找到默認網關F0/0接口的MAC地址也“耽擱”了一些時間,這也是爲什麼我們在第一次ping網絡上某臺主機/設備的時候通常會看到第一個數據包會出現“request timed out!”(請求超時!)的情況。最後主機A完成MAC地址解析後將該幀發送到網絡A上,該幀的具體封裝如下:
目的MAC: 路由器F0/0接口 |
源MAC: 主機A的MAC地址 |
源IP: 192.168.0.5 |
目的IP: 1.1.1.5 |
ICMP報頭 | (主機A) Ping 1.1.1.5 |
因爲該幀的目的MAC地址是F0/0的MAC地址,所以只有路由器的F0/0接口接收並處理該數據幀。路由器將該幀解封裝並查看網絡層的封裝信息,路由器看到該數據包網絡層封裝的目的地址是1.1.1.5。路由器爲了將這個數據包轉發到1.1.1.5,使用前面提到的“與運算”的方法進行計算,依據計算結果判斷目標地址1.1.1.5對於路由器自己來說在本地網絡還是在遠程網絡。路由器所做“與運算”過程簡述如下:
路由器的F0/0接口上的IP地址192.168.0.1與F0/0接口的子網掩碼255.255.255.0作“與運算”得到“結果1”;目標地址1.1.1.5與路由器F0/0接口的子網掩碼255.255.255.0作“與運算”得到“結果2”;“結果1”與“結果2”並不相同,證明目標地址1.1.1.5並不處在路由器的F0/0接口所在的網絡A。
路由器的另一個接口F0/1的IP地址1.1.1.1與F0/1接口的子網掩碼255.255.255.0作“與運算”得到“結果3”;目標地址1.1.1.5與F0/1接口上
的子網掩碼255.255.255.0作“與運算”得到“結果4”;“結果3”與“結果4”相同,證明目標地址1.1.1.5處在路由器的F0/1接口所在的網絡B。這也就意味着路由器B只需將發送給1.1.1.5的數據包從F0/1接口發出去就OK了。我們將路由器的這種路由稱爲直接路由。
路由器得出上述結論後立刻執行封裝,封裝的具體信息如下:
目的MAC: 主機B的MAC地址 |
源MAC: 路由器F0/1接口 |
源IP地址 192.168.0.5 |
目的IP地址 1.1.1.5 |
ICMP報頭 | (主機A) Ping 1.1.1.5 |
在以上路由器封裝的具體信息中的目的MAC地址是主機B的MAC地址。如果路由器在ARP緩存表中並未查到主機B的硬件MAC地址,則路由器仍然會像主機A查詢路由器F0/0接口硬件MAC地址一樣發送ARP請求來查詢主機B的MAC地址。關於路由器對主機B 硬件MAC地址的查詢過程在這裏就不再重複了。
這樣主機B就收到了該數據幀,主機B對該幀進行解封裝看到了網絡層封裝的目的IP地址,知道這個數據包的目的地是自己後,主機B繼續對其拆封裝並查看ICMP報頭內的信息得出結論:這是一個請求自己進行反饋的數據包,需要自己將這條“數據包已到達主機B”的信息回饋給主機A。因此主機B爲了將回饋信息順利送達主機A需要經過如封裝:
目的MAC: 路由器F0/1接口 |
源MAC: 主機B的MAC地址 |
源IP: 1.1.1.5 |
目的IP: 192.168.0.5 |
ICMP報頭 | 對(主機A) Ping 1.1.1.5的應答 |
主機B在發送應答數據包時封裝的目的MAC地址是路由器F0/1接口的MAC地址,這也是主機B通過路由判斷和與運算得出的結論,對於主機B來說路由器F0/1接口是它的下一跳。
路由器F0/1接口在收到主機B發來的數據包後爲了將其轉發給主機A再次進行封裝,具體的封裝信息如下:
目的MAC: 主機A的MAC地址 |
源MAC: 路由器F0/0接口 |
源IP: 1.1.1.5 |
目的IP: 192.168.0.5 |
ICMP報頭 | 對(主機A) Ping 1.1.1.5的應答 |
從主機A到路由器再到主機B執行的封裝過程中我們可以看出網絡層封裝的信息是始終不變的:源IP是192.168.0.5 目的IP是1.1.1.5。始終變化的是一跳一跳的硬件MAC地址。從主機B到路由器再到主機A執行的封裝過程中我們同樣可以看出網絡層封裝的信息也是始終不變的:源IP是1.1.1.5目的IP是192.168.0.5。始終變化的還是一跳一跳的硬件MAC地址。
以上我們在IP路由封裝的過程中得到的這一結論並不適用於另外一個網絡技術——NAT(網絡地址轉換)。關於NAT我們將在其他的文章中繼續討論。