9.6. 封包與路由

IP 位址說明了一則訊息是要給的。真正負責遞送它的機制稱為路由,這是一個逐跳的過程,封包藉此從傳送端的本地網路一路傳到接收端的本地網路,後者可能相距非常遙遠。

9.6.1. 簡述封包

封包是 IP 層的工作單位——一段帶有小型標頭與酬載(payload)的位元組。標頭中有兩個與路由相關的欄位:

  • 來源 IP 位址(封包從何處而來)。

  • 目的地 IP 位址(封包要往何處去)。

酬載就是傳輸層要求網路層遞送的任何內容。封包標頭也包含一個存活時間(time-to-live)計數器、一個涵蓋標頭的檢查碼,以及少數幾個控制旗標。這些都不是相機的 Python 程式碼會直接觸及的東西。

封包除了「我們盡力了」之外不保證任何事——它們可能遺失、重複,或以亂序遞送。可靠性與排序是上層傳輸層要解決的問題;網路層只是盡其所能地把每個封包朝目的地轉發。

9.6.2. 逐跳

封包離開相機,抵達第一台不位於相機本地網段上的裝置:預設閘道。(前一頁 曾提到,網路建立時 DHCP 會把閘道的位址交給相機。)那台裝置就是路由器——它的工作是接收封包、查看其目的地,並把它們往前轉發。

一張顯示五個方塊的圖。左側是一台標示為「10.0.0.42」的相機。它連接到一台標示為「10.0.0.1 / 203.0.113.5」的路由器。接著是中間兩台未命名的路由器序列。然後是一台標示為「198.51.100.1 / 198.51.100.x」的路由器。最後是一台標示為「198.51.100.20」的伺服器。一個標示為「目的地:198.51.100.20」的箭頭沿著這條鏈由左至右移動。

一個從相機送往目的地的封包在路由器之間跳躍,每一台都更近一步。

路由器有一張路由表——一份「對於符合此模式的目的地,把封包從此介面送出」的清單。對於與相機在同一網路上的目的地,該條目會說「把它送回它進來的那條纜線」。對於更廣大網際網路上的目的地,該條目會說「把它送往上游路由器」。對於已知模式的目的地(企業 VPN、特定商業夥伴的網路、衛星連線),路由器可能有更具體的條目,會覆寫預設行為。

上游路由器做同樣的事。下一台也是。再下一台也是。每一跳的形態都相同:接收封包、在表中查詢目的地、從正確的介面送出。最終封包會抵達一台位於與目的地 IP 相同本地網段上的路由器。那台路由器完成最後一跳的遞送,目的地收到封包,這趟旅程就結束了。

9.6.3. 端點並不知道路由

一台把封包送往遠端伺服器的相機,並不知道封包將如何抵達那裡。它只知道目的地 IP 以及自己預設閘道的位址。介於其間的一切——哪些路由器、哪些光纖、哪些海底纜線——都是路徑沿途的路由器根據它們自己的表,邊走邊決定的。路由器本身也只知道它們的直接鄰居,以及常見目的地的大致方向;網際網路上沒有任何單一裝置擁有它的完整地圖。

正是這種去中心化,使得網路在個別路徑失效時仍能持續運作。中途某處斷掉的纜線,在少數幾台路由器上變成一次重新路由事件;端點完全察覺不到。這也是為什麼一個從東京相機送往都柏林伺服器的封包能夠成功,而雙方都不知道中間隔著哪些國家。

9.6.4. 這對 Python 指令碼意味著什麼

相機在網路層的工作可以歸結為:

  • 擁有一個 IP 位址。

  • 知道預設閘道的位址(DHCP 會自動填入這項資訊)。

  • 把定址給任何 IP 的對外封包交給該閘道,並信任路徑的其餘部分。

指令碼從不挑選路由、從不指名某個中間跳躍點,也從不看見中途的路由器。它把目的地 IP 寫到封包上,接下來就由網路層接手。從 Python 指令碼的角度來看,整個路由不過是相機所加入網路的一項屬性——「閘道會把封包送到對我有用的某處」。

緊接其後的傳輸層假設路由就是能運作,並在此基礎之上建立可靠性、排序以及程式對程式的定址。