ipaddress 模組簡介¶
- 作者:
Peter Moody
- 作者:
Nick Coghlan
建立地址/網路/介面物件¶
由於 ipaddress
是一個用於檢查和操作 IP 地址的模組,因此您要做的第一件事就是建立一些物件。您可以使用 ipaddress
從字串和整數建立物件。
關於 IP 版本的說明¶
對於不熟悉 IP 定址的讀者來說,瞭解網際網路協議 (IP) 目前正在從協議版本 4 過渡到版本 6 這一點很重要。這種過渡主要是因為協議版本 4 無法提供足夠的地址來滿足全球的需求,尤其是考慮到直接連線到網際網路的裝置數量不斷增加。
解釋兩種協議版本之間差異的詳細資訊超出了本介紹的範圍,但讀者至少需要了解這兩種版本確實存在,並且有時有必要強制使用其中一個版本。
IP 主機地址¶
地址,通常稱為“主機地址”,是處理 IP 定址時最基本的單位。建立地址最簡單的方法是使用 ipaddress.ip_address()
工廠函式,該函式會根據傳入的值自動確定是建立 IPv4 還是 IPv6 地址
>>> ipaddress.ip_address('192.0.2.1')
IPv4Address('192.0.2.1')
>>> ipaddress.ip_address('2001:DB8::1')
IPv6Address('2001:db8::1')
地址也可以直接從整數建立。假定適合 32 位的值是 IPv4 地址
>>> ipaddress.ip_address(3221225985)
IPv4Address('192.0.2.1')
>>> ipaddress.ip_address(42540766411282592856903984951653826561)
IPv6Address('2001:db8::1')
要強制使用 IPv4 或 IPv6 地址,可以直接呼叫相關類。這對於強制為小整數建立 IPv6 地址特別有用
>>> ipaddress.ip_address(1)
IPv4Address('0.0.0.1')
>>> ipaddress.IPv4Address(1)
IPv4Address('0.0.0.1')
>>> ipaddress.IPv6Address(1)
IPv6Address('::1')
定義網路¶
主機地址通常分組到 IP 網路中,因此 ipaddress
提供了一種建立、檢查和操作網路定義的方法。IP 網路物件由定義屬於該網路的主機地址範圍的字串構建。該資訊最簡單的形式是“網路地址/網路字首”對,其中字首定義了用於確定地址是否屬於網路的領先位數,網路地址定義了這些位的預期值。
與地址一樣,提供了一個工廠函式,可自動確定正確的 IP 版本
>>> ipaddress.ip_network('192.0.2.0/24')
IPv4Network('192.0.2.0/24')
>>> ipaddress.ip_network('2001:db8::0/96')
IPv6Network('2001:db8::/96')
網路物件不能設定任何主機位。這實際上意味著 192.0.2.1/24
不描述一個網路。此類定義被稱為介面物件,因為網路上的 IP 表示法通常用於描述給定網路上計算機的網路介面,下一節將進一步描述。
預設情況下,嘗試建立設定了主機位的網路物件將導致引發 ValueError
。要請求將附加位強制為零,可以將標誌 strict=False
傳遞給建構函式
>>> ipaddress.ip_network('192.0.2.1/24')
Traceback (most recent call last):
...
ValueError: 192.0.2.1/24 has host bits set
>>> ipaddress.ip_network('192.0.2.1/24', strict=False)
IPv4Network('192.0.2.0/24')
雖然字串形式提供了顯著的靈活性,但網路也可以像主機地址一樣用整數定義。在這種情況下,網路被認為只包含由整數標識的單個地址,因此網路字首包含整個網路地址
>>> ipaddress.ip_network(3221225984)
IPv4Network('192.0.2.0/32')
>>> ipaddress.ip_network(42540766411282592856903984951653826560)
IPv6Network('2001:db8::/128')
與地址一樣,可以透過直接呼叫類建構函式而不是使用工廠函式來強制建立特定型別的網路。
主機介面¶
如上所述,如果您需要描述特定網路上的地址,則地址和網路類都不足。像 192.0.2.1/24
這樣的表示法通常被網路工程師和為防火牆和路由器編寫工具的人用作“網路 192.0.2.0/24
上的主機 192.0.2.1
”的簡寫。因此,ipaddress
提供了一組混合類,將地址與特定網路相關聯。建立介面與定義網路物件的介面相同,只是地址部分不受限於網路地址。
>>> ipaddress.ip_interface('192.0.2.1/24')
IPv4Interface('192.0.2.1/24')
>>> ipaddress.ip_interface('2001:db8::1/96')
IPv6Interface('2001:db8::1/96')
接受整數輸入(與網路一樣),並且可以透過直接呼叫相關建構函式來強制使用特定 IP 版本。
檢查地址/網路/介面物件¶
您已經費心建立了一個 IPv(4|6)(地址|網路|介面) 物件,所以您可能想獲取有關它的資訊。ipaddress
試圖使這變得簡單直觀。
提取 IP 版本
>>> addr4 = ipaddress.ip_address('192.0.2.1')
>>> addr6 = ipaddress.ip_address('2001:db8::1')
>>> addr6.version
6
>>> addr4.version
4
從介面獲取網路
>>> host4 = ipaddress.ip_interface('192.0.2.1/24')
>>> host4.network
IPv4Network('192.0.2.0/24')
>>> host6 = ipaddress.ip_interface('2001:db8::1/96')
>>> host6.network
IPv6Network('2001:db8::/96')
查詢網路中有多少個單獨的地址
>>> net4 = ipaddress.ip_network('192.0.2.0/24')
>>> net4.num_addresses
256
>>> net6 = ipaddress.ip_network('2001:db8::0/96')
>>> net6.num_addresses
4294967296
迭代網路上“可用”的地址
>>> net4 = ipaddress.ip_network('192.0.2.0/24')
>>> for x in net4.hosts():
... print(x)
192.0.2.1
192.0.2.2
192.0.2.3
192.0.2.4
...
192.0.2.252
192.0.2.253
192.0.2.254
獲取子網掩碼(即與網路字首對應的設定位)或主機掩碼(不屬於子網掩碼的任何位)
>>> net4 = ipaddress.ip_network('192.0.2.0/24')
>>> net4.netmask
IPv4Address('255.255.255.0')
>>> net4.hostmask
IPv4Address('0.0.0.255')
>>> net6 = ipaddress.ip_network('2001:db8::0/96')
>>> net6.netmask
IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff::')
>>> net6.hostmask
IPv6Address('::ffff:ffff')
擴充套件或壓縮地址
>>> addr6.exploded
'2001:0db8:0000:0000:0000:0000:0000:0001'
>>> addr6.compressed
'2001:db8::1'
>>> net6.exploded
'2001:0db8:0000:0000:0000:0000:0000:0000/96'
>>> net6.compressed
'2001:db8::/96'
雖然 IPv4 不支援擴充套件或壓縮,但相關物件仍然提供相關屬性,以便版本中立的程式碼可以輕鬆確保 IPv6 地址使用最簡潔或最詳細的形式,同時仍能正確處理 IPv4 地址。
作為地址列表的網路¶
有時將網路視為列表很有用。這意味著可以像這樣對其進行索引
>>> net4[1]
IPv4Address('192.0.2.1')
>>> net4[-1]
IPv4Address('192.0.2.255')
>>> net6[1]
IPv6Address('2001:db8::1')
>>> net6[-1]
IPv6Address('2001:db8::ffff:ffff')
這也意味著網路物件適用於使用像這樣的列表成員資格測試語法
if address in network:
# do something
根據網路字首有效地執行包含性測試
>>> addr4 = ipaddress.ip_address('192.0.2.1')
>>> addr4 in ipaddress.ip_network('192.0.2.0/24')
True
>>> addr4 in ipaddress.ip_network('192.0.3.0/24')
False
比較操作¶
ipaddress
提供了一些簡單、希望能直觀的方法來比較物件,在有意義的情況下
>>> ipaddress.ip_address('192.0.2.1') < ipaddress.ip_address('192.0.2.2')
True
如果您嘗試比較不同版本或不同型別的物件,則會引發 TypeError
異常。
將 IP 地址與其他模組一起使用¶
使用 IP 地址的其他模組(例如 socket
)通常不會直接接受此模組中的物件。相反,它們必須被強制轉換為其他模組將接受的整數或字串
>>> addr4 = ipaddress.ip_address('192.0.2.1')
>>> str(addr4)
'192.0.2.1'
>>> int(addr4)
3221225985
例項建立失敗時獲取更多詳細資訊¶
當使用與版本無關的工廠函式建立地址/網路/介面物件時,任何錯誤都將報告為 ValueError
,並帶有一個通用錯誤訊息,簡單地表示傳入的值未被識別為該型別的物件。缺少特定錯誤的原因是,為了提供有關為什麼它被拒絕的更多詳細資訊,有必要知道該值 應該 是 IPv4 還是 IPv6。
為了支援獲取此附加詳細資訊有用的用例,各個類建構函式實際上會引發 ValueError
的子類 ipaddress.AddressValueError
和 ipaddress.NetmaskValueError
,以精確指示定義的哪個部分解析失敗。
直接使用類建構函式時,錯誤訊息會明顯更詳細。例如
>>> ipaddress.ip_address("192.168.0.256")
Traceback (most recent call last):
...
ValueError: '192.168.0.256' does not appear to be an IPv4 or IPv6 address
>>> ipaddress.IPv4Address("192.168.0.256")
Traceback (most recent call last):
...
ipaddress.AddressValueError: Octet 256 (> 255) not permitted in '192.168.0.256'
>>> ipaddress.ip_network("192.168.0.1/64")
Traceback (most recent call last):
...
ValueError: '192.168.0.1/64' does not appear to be an IPv4 or IPv6 network
>>> ipaddress.IPv4Network("192.168.0.1/64")
Traceback (most recent call last):
...
ipaddress.NetmaskValueError: '64' is not a valid netmask
但是,這兩個模組特定的異常都將 ValueError
作為它們的父類,因此如果您不關心特定型別的錯誤,您仍然可以編寫如下程式碼
try:
network = ipaddress.IPv4Network(address)
except ValueError:
print('address/netmask is invalid for IPv4:', address)