9.5. IP 位址

硬體位址可以在同一條本地纜線或無線電蜂巢上的眾多裝置中辨識出特定的一個。對於這項工作它很稱職,但一旦超出本地網段就毫無用處:隔壁棟建築的交換器無法藉由它來路由,因為讓交換器學習 MAC 位址的底層機制只在單一網段內運作。

網路層以第二種位址來解決這個問題,這種位址與裝置接在哪條纜線上無關。這種位址的名稱是網際網路協定位址(Internet Protocol address),或稱 IP 位址,而「網際網路協定」這一半則命名了網際網路上每台主機在傳送或轉發位址時所遵循的一整套規則。目前的網際網路同時並行使用兩種版本的定址方案——IPv4(較舊的形式,在小型網路上仍佔主導地位)與 IPv6(較新的形式,正逐步取代前者)。

9.5.1. IP 位址是什麼

IP 位址是一個夠大的數字,足以唯一識別網際網路上的任何裝置。它以人類可讀的形式書寫(本節其餘部分都使用這種形式),但在封包標頭中它只是一個固定大小的整數。

  • IPv4 位址長度為 32 位元,書寫成以點分隔的四個十進位數字,每個數字為一個位元組:

    192.168.1.42
    8.8.8.8
    10.0.0.1
    

    三十二位元可提供大約四十億個可能的位址,這在 1970 年代設計 IPv4 時聽起來綽綽有餘,但到了 2010 年代初期就已經不夠用了。

  • IPv6 位址長度為 128 位元,書寫成以冒號分隔的八組各四個十六進位數字:

    2001:0db8:85a3:0000:0000:8a2e:0370:7334
    

    連續的零可以縮寫為 ::,而每一組中的前導零可以省略,因此上面的位址通常會寫成 2001:db8:85a3::8a2e:370:7334

除此之外,這兩個位址家族就像不同的語言;IPv4 主機若沒有閘道的協助,就無法直接傳送封包給 IPv6 主機。相機的 networksocket 模組同時支援兩者。本教學在範例中使用 IPv4,因為相機要加入的大多數本地網路目前仍只支援 IPv4,但只要把位址換掉,後續的一切對 IPv6 來說運作方式完全相同。

9.5.2. IP 位址的用途

IP 位址說明了某個封包要送往網際網路上的哪一台主機。一台不知道如何直接抵達目的地的路由器,知道其他某台路由器大概知道,於是便把封包轉發到那裡。封包在路由器之間跳躍,每一台都離目的地更近一點,直到某台位於目的地本地網段上的路由器完成最後一跳的遞送。

正是這種逐跳的行為,讓網際網路得以成為一個大型網路,而非許多互不相通的小島。下一頁 會說明這些跳躍是如何選擇的;本頁只談位址本身。

9.5.3. 相機如何取得位址

剛加入 Wi-Fi 網路的相機,必須先取得 IP 位址才能與任何裝置溝通。通常有兩種方式可以做到這一點。

第一種是自動指派。相機向本地網路請求一個位址;負責發放位址的裝置就是路由器——將本地網路連接到更廣大網際網路的那個盒子。在大多數家庭與小型辦公室的設定中,同一個實體盒子也兼任有線裝置接入的交換器,以及無線裝置關聯的 Wi-Fi 存取點,因此「路由器」、「交換器」與「存取點」可能都是同一件硬體。路由器運行一項稱為 DHCP(動態主機組態協定,Dynamic Host Configuration Protocol)的小型服務,它維護一個可用位址池,為每台新到的裝置挑選一個位址,並租用給它一段固定的時間。在 DHCP 進行的同時,路由器也會交給相機另外幾項有用的組態資訊:

  • 當目的地不在本地網路上時,要把對外流量送往的位址(預設閘道,也就是路由器自身的位址);以及

  • 一或多個名稱伺服器的位址,它們負責把像 example.com 這樣人類可讀的名稱轉換成 IP 位址。這項名稱查詢服務稱為 DNS(網域名稱系統,Domain Name System),名稱與 DNS 會詳細說明它。

這一切都在連線建立的過程中自動發生。相機不必明確地去請求其中任何一項;在前一頁的範例中,當 isconnected() 回傳 True 的那一刻,相機就已經擁有它的位址、它的閘道以及它的名稱伺服器了。

第二種選項是靜態組態。某些部署希望相機擁有已知的位址,好讓其他裝置不必先查詢就能連上它。ipconfig() 方法可以手動設定位址、閘道與名稱伺服器:

wlan.ipconfig(addr4=("192.168.1.50/24", "192.168.1.1"))
wlan.ipconfig(dns="192.168.1.1")

靜態組態很脆弱(兩台裝置不小心被指派了相同的位址就會發生衝突)。除非出現特定理由需要覆寫,否則請選用 DHCP 的預設做法。

相機一旦取得 IP 位址,就加入了網際網路(或至少加入了本地網路的那一部分)。其他裝置現在可以用該位址把封包定址給它,它也可以把封包定址給它們。

9.5.4. 網路遮罩與 /24

上面靜態範例中位址結尾的 /24 就是網路遮罩。IP 位址本身並未說明本地網路在哪裡結束——192.168.1.50 可能是小型家庭網路上數百個位址之一,也可能是較大型網路上數千個位址之一。網路遮罩說明了位址中有多少部分命名網路,又有多少部分命名其中的主機

/24 表示「32 位元中的前 24 位元命名網路;最後 8 位元命名主機」。對於 192.168.1.50/24,這會把位址切分為代表網路的 192.168.1 與代表主機的 .50,在同一個本地網路上為約 254 台裝置留出空間。/16 會為主機那一半留下更多位元,能在一個網路上容納多得多的裝置;/30 則只留下兩個主機位址,恰好容納一條點對點連線。

網路遮罩通常也會寫成與位址相同的點分表示法的四位元組數字。/24 等同於 255.255.255.0——把每個位元組讀作「所有屬於網路那一半的位元」。這兩種形式可以互換;下一小節中的 ipconfig() 讀取器剛好回傳四位元組的形式。

這個切分為何如此重要——裝置如何利用網路遮罩來判斷某個目的地是在本地網路上,還是需要透過閘道對外送出,以及為什麼大多數家庭網路最終都採用 /24——這些都會在 私有網路與 NAT 中說明。

9.5.5. 讀回位址

不帶引數的 ipconfig() 方法會回傳目前作用中的組態。addr4 檢視會回傳 IP 位址與網路遮罩:

>>> wlan.ipconfig("addr4")
('192.168.1.50', '255.255.255.0')