使用 Python 的 ipaddress 模塊學習 IP 地址概念

      網友投稿 1561 2025-04-02

      目錄


      理論與實踐中的 IP 地址

      IP地址的機制

      Python ipaddress 模塊

      IP 網絡和接口

      CIDR 表示法

      循環網絡

      子網

      主機接口

      特殊地址范圍

      引擎蓋下的 Python ipaddress 模塊

      組合的核心作用

      擴展 IPv4 地址

      結論

      進一步閱讀

      Python 的ipaddress模塊是 Python 標準庫中被低估的珍寶。您不必是一個成熟的網絡工程師,就可以在野外暴露于 IP 地址。IP 地址和網絡在軟件開發和基礎設施中無處不在。它們是計算機如何相互尋址的基礎。

      邊做邊學是掌握IP地址的有效方法。該ipaddress模塊允許您通過將 IP 地址作為 Python 對象查看和操作來實現這一點。在本教程中,您將通過使用 Pythonipaddress模塊的一些功能更好地掌握 IP 地址。

      在本教程中,您將學習:

      如何IP地址的工作,無論是在理論上還是在Python代碼

      IP 網絡如何表示 IP 地址組以及如何檢查兩者之間的關系

      Python 的ipaddress模塊如何巧妙地使用經典的設計模式,讓你事半功倍

      要繼續,您只需要 Python 3.3 或更高版本,因為它ipaddress已添加到該版本的 Python 標準庫中。本教程中的示例是使用Python 3.8生成的。

      理論與實踐中的 IP 地址

      如果您只記得有關 IP 地址的一個概念,那么請記住這一點:IP 地址是一個整數。這條信息將幫助您更好地理解 IP 地址的功能以及它們如何表示為 Python 對象。

      在你跳入任何 Python 代碼之前,看看這個概念在數學上充實是有幫助的。如果您在這里只是為了了解如何使用ipaddress模塊的一些示例,那么您可以跳到下一部分,關于使用模塊本身。

      IP地址的機制

      您在上面看到 IP 地址歸結為一個整數。更完整的定義是IPv4 地址是一個 32 位整數,用于表示網絡上的主機。術語主機有時與地址同義。

      因此,有 2?32 個可能的 IPv4 地址,從 0 到 4,294,967,295(其中上限為 2?32?- 1)。但這是人類的教程,而不是機器人。沒有人想 ping IP 地址0xdc0e0925。

      表達 IPv4 地址的更常見方法是使用四點表示法,它由四個點分隔的十進制整數組成:

      220.14.9.37

      220.14.9.37不過,地址代表的底層整數并不是很明顯。從公式上講,您可以將 IP 地址220.14.9.37分成四個八位字節組成部分:

      >>> ( ... 220 * (256 ** 3) + ... 14 * (256 ** 2) + ... 9 * (256 ** 1) + ... 37 * (256 ** 0) ... ) 3691907365

      如上所示,地址220.14.9.37代表整數 3,691,907,365。每個八位字節是一個byte,或一個從 0 到 255 的數字。鑒于此,您可以推斷出 IPv4 地址的最大值為255.255.255.255(或FF.FF.FF.FF十六進制表示法),而最小值為0.0.0.0。

      接下來,您將看到 Python 的ipaddress模塊如何為您執行此計算,從而允許您使用人類可讀的形式并讓地址算術在視線之外發生。

      Pythonipaddress模塊

      接下來,您可以獲取計算機的外部 IP 地址以在命令行中使用:

      $ curl -sS ifconfig.me/ip 220.14.9.37

      這會從站點ifconfig.me請求您的 IP 地址,該地址可用于顯示有關您的連接和網絡的一系列詳細信息。

      注意:為了技術上的正確性,這很可能不是您計算機自己的公共 IP 地址。如果您的連接位于NATed路由器后面,那么最好將其視為您訪問 Internet 的“代理”IP。

      現在打開一個 Python REPL。您可以使用IPv4Address該類來構建一個封裝地址的 Python 對象:

      >>>

      >>> from ipaddress import IPv4Address >>> addr = IPv4Address("220.14.9.37") >>> addr IPv4Address('220.14.9.37')

      將str諸如此類傳遞"220.14.9.37"給IPv4Address構造函數是最常見的方法。但是,該類也可以接受其他類型:

      >>> IPv4Address(3691907365) # From an int IPv4Address('220.14.9.37') >>> IPv4Address(b"\xdc\x0e\t%") # From bytes (packed form) IPv4Address('220.14.9.37')

      雖然從人類可讀的構造str可能是更常見的方式,但bytes如果您正在處理諸如TCP packet data 之類的東西,您可能會看到輸入。

      上面的轉換也可以在另一個方向上進行:

      >>>

      >>> int(addr) 3691907365 >>> addr.packed b'\xdc\x0e\t%'

      除了允許往返輸入和輸出到不同的 Python 類型之外, 的實例IPv4Address也是可散列的。這意味著您可以將它們用作映射數據類型(例如字典)中的鍵:

      >>> hash(IPv4Address("220.14.9.37")) 4035855712965130587 >>> num_connections = { ... IPv4Address("220.14.9.37"): 2, ... IPv4Address("100.201.0.4"): 16, ... IPv4Address("8.240.12.2"): 4, ... }

      最重要的是,IPv4Address還實現的方法,其允許使用底層整數比較:

      >>> IPv4Address("220.14.9.37") > IPv4Address("8.240.12.2") True >>> addrs = ( ... IPv4Address("220.14.9.37"), ... IPv4Address("8.240.12.2"), ... IPv4Address("100.201.0.4"), ... ) >>> for a in sorted(addrs): ... print(a) ... 8.240.12.2 100.201.0.4 220.14.9.37

      您可以使用任何標準比較運算符來比較地址對象的整數值。

      注意:本教程重點介紹 Internet 協議版本 4 (IPv4) 地址。還有一些 IPv6 地址,它們是 128 位而不是 32 位,并以標題形式表示,例如2001:0:3238:dfe1:63::fefb.?由于地址的算術基本相同,因此本教程從等式中刪除了一個變量,重點關注 IPv4 地址。

      該ipaddress模塊具有更靈活的工廠函數,?ip_address(),它接受一個表示 IPv4 或 IPv6 地址的參數,并盡力分別返回一個IPv4Address或一個IPv6Address實例。

      在本教程中,您將切入正題并IPv4Address直接使用它構建地址對象。

      正如你在上面看到的,構造函數本身IPv4Address是簡短而甜蜜的。當您開始將地址歸入組或網絡時,事情就會變得更有趣。

      IP 網絡和接口

      甲網絡是一組IP地址。網絡被描述和顯示為連續的地址范圍。例如,一個網絡可以由地址的192.4.2.0通過192.4.2.255,含有256個地址的網絡。

      您可以通過上下 IP 地址識別網絡,但是如何以更簡潔的約定來顯示它呢?這就是 CIDR 表示法的用武之地。

      CIDR 表示法

      網絡是使用所定義的網絡地址加一個前綴在無類別域間路由(CIDR)表示法:

      >>>

      >>> from ipaddress import IPv4Network >>> net = IPv4Network("192.4.2.0/24") >>> net.num_addresses 256

      CIDR 表示法將網絡表示為/。該路由前綴(或前綴長度,或者只是前綴),這是在這種情況下,24歲,是用來回答問題前幾位,如某個地址是否是網絡的一部分,或者有多少地址駐留在網絡中的計數。(這里的前導位是指從二進制整數左側開始計數的前N位。)

      您可以通過以下.prefixlen屬性找到路由前綴:

      >>> net.prefixlen 24

      讓我們直接進入一個例子。地址192.4.2.12在網絡中192.4.2.0/24嗎?在這種情況下,答案是肯定的,因為 的前 24 位192.4.2.12是前三個八位字節 (?192.4.2)。使用/24前綴,您可以簡單地切掉最后一個八位字節并查看192.4.2.xxx部分匹配。

      換個角度看,/24前綴轉換為網絡掩碼,顧名思義,該掩碼用于屏蔽正在比較的地址中的位:

      >>>

      >>> net.netmask IPv4Address('255.255.255.0')

      您可以比較前導位以確定地址是否屬于網絡的一部分。如果前導位匹配,則該地址是網絡的一部分:

      11000000 00000100 00000010 00001100 # 192.4.2.12 # Host IP address 11000000 00000100 00000010 00000000 # 192.4.2.0 # Network address | ^ 24th bit (stop here!) |_________________________| | These bits match

      上面,最后 8 位192.4.2.12被屏蔽(用0)并在比較中被忽略。再一次,Python 為ipaddress您節省了數學體操并支持慣用的成員資格測試:

      >>>

      >>> net = IPv4Network("192.4.2.0/24") >>> IPv4Address("192.4.2.12") in net True >>> IPv4Address("192.4.20.2") in net False

      這是由運算符重載的寶藏實現的,它IPv4Network定義__contains__()了允許使用in運算符進行成員資格測試。

      在 CIDR 表示法中192.4.2.0/24,該192.4.2.0部分是網絡地址,用于標識網絡:

      >>> net.network_address IPv4Address('192.4.2.0')

      正如您在上面192.4.2.0看到的,當掩碼應用于主機 IP 地址時,網絡地址可以看作是預期的結果:

      11000000 00000100 00000010 00001100 # Host IP address 11111111 11111111 11111111 00000000 # Netmask, 255.255.255.0 or /24 11000000 00000100 00000010 00000000 # Result (compared to network address)

      當您這樣思考時,您可以看到/24前綴實際上是如何轉換為 true 的IPv4Address:

      >>>

      >>> net.prefixlen 24 >>> net.netmask IPv4Address('255.255.255.0') # 11111111 11111111 11111111 00000000

      事實上,如果你喜歡它,你可以IPv4Network直接從兩個地址構造一個:

      >>> IPv4Network("192.4.2.0/255.255.255.0") IPv4Network('192.4.2.0/24')

      上面,192.4.2.0是網絡地址,255.255.255.0而是網絡掩碼。

      在網絡頻譜的另一端是其最終地址或廣播地址,這是一個可用于與其網絡上的所有主機通信的地址:

      >>>

      >>> net.broadcast_address IPv4Address('192.4.2.255')

      關于網絡掩碼還有一點值得一提。您最??吹降那熬Y長度是 8 的倍數:

      但是,0 到 32 之間的任何整數都是有效的,盡管不太常見:

      >>>

      >>> net = IPv4Network("100.64.0.0/10") >>> net.num_addresses 4194304 >>> net.netmask IPv4Address('255.192.0.0')

      在本節中,您了解了如何構建IPv4Network實例并測試某個 IP 地址是否位于其中。在下一節中,您將學習如何遍歷網絡中的地址。

      循環網絡

      本IPv4Network類支持迭代,這意味著你可以在其個人地址迭代for循環:

      >>>

      >>> net = IPv4Network("192.4.2.0/28") >>> for addr in net: ... print(addr) ... 192.4.2.0 192.4.2.1 192.4.2.2 ... 192.4.2.13 192.4.2.14 192.4.2.15

      類似地,net.hosts()返回一個生成器,該生成器將生成上面顯示的地址,不包括網絡和廣播地址:

      >>>

      >>> h = net.hosts() >>> type(h) >>> next(h) IPv4Address('192.4.2.1') >>> next(h) IPv4Address('192.4.2.2')

      在下一節中,您將深入研究一個與網絡密切相關的概念:子網。

      子網

      一個子網是一個IP網絡的細分:

      >>>

      >>> small_net = IPv4Network("192.0.2.0/28") >>> big_net = IPv4Network("192.0.0.0/16") >>> small_net.subnet_of(big_net) True >>> big_net.supernet_of(small_net) True

      上面,small_net只包含16個地址,足夠你和你周圍的幾個小隔間了。相反,big_net包含 65,536 個地址。

      實現子網劃分的一種常見方法是取一個網絡并將其前綴長度增加 1。讓我們以維基百科中的這個例子為例:

      IPv4 網絡子網劃分

      這個例子從一個/24網絡開始:

      net = IPv4Network("200.100.10.0/24")

      通過將前綴長度從 24 增加到 25 來劃分子網涉及移動位以將網絡分成更小的部分。這在數學上有點毛茸茸的。幸運的是,IPv4Network這很簡單,因為.subnets()在子網上返回一個迭代器:

      >>>

      >>> for sn in net.subnets(): ... print(sn) ... 200.100.10.0/25 200.100.10.128/25

      您還可以告訴.subnets()新前綴應該是什么。更高的前綴意味著更多和更小的子網:

      >>> for sn in net.subnets(new_prefix=28): ... print(sn) ... 200.100.10.0/28 200.100.10.16/28 200.100.10.32/28 ... 200.100.10.208/28 200.100.10.224/28 200.100.10.240/28

      除了地址和網絡之外,ipaddress接下來您將看到該模塊的第三個核心部分。

      使用 Python 的 ipaddress 模塊學習 IP 地址概念

      主機接口

      最后但同樣重要的是,Python 的ipaddress模塊導出一個IPv4Interface類來表示主機接口。一個主機接口是描述在一個緊湊的形式的方式,在主機IP地址,它坐落在一個網絡:

      >>>

      >>> from ipaddress import IPv4Interface >>> ifc = IPv4Interface("192.168.1.6/24") >>> ifc.ip # The host IP address IPv4Address('192.168.1.6') >>> ifc.network # Network in which the host IP resides IPv4Network('192.168.1.0/24')

      上面的192.168.1.6/24意思是“192.168.1.6網絡中的 IP 地址192.168.1.0/24”。

      注意:在計算機網絡的上下文中,接口也可以指網絡接口,最常見的是網絡接口卡 (NIC)。如果你曾經使用過的ifconfig工具(* nix中)或ipconfig(Windows)中,那么你可能知道一個名字你如eth0,en0或ens3。這兩種類型的接口是不相關的。

      換句話說,單獨的 IP 地址并不能告訴您該地址位于哪個或哪些網絡,并且網絡地址是一組 IP 地址而不是單個 IP 地址。這IPv4Interface為您提供了一種通過 CIDR 表示法同時表示單個主機 IP 地址及其網絡的方法。

      特殊地址范圍

      既然您對 IP 地址和網絡都有較高的了解,那么了解并非所有 IP 地址都是平等的——有些是特殊的,了解這一點也很重要。

      互聯網號碼分配機構 (IANA) 與互聯網工程任務組 (IETF) 協同監督不同地址范圍的分配。IANA 的IPv4 特殊用途地址注冊表是一個非常重要的表格,規定某些地址范圍應具有特殊含義。

      一個常見的例子是私有地址。專用 IP 地址用于網絡上不需要連接到公共 Internet 的設備之間的內部通信。以下范圍保留供私人使用:

      一個隨機選擇的例子是10.243.156.214。那么,你怎么知道這個地址是私人的呢?您可以確認它在10.0.0.0/8范圍內:

      >>> IPv4Address("10.243.156.214") in IPv4Network("10.0.0.0/8") True

      第二種特殊地址類型是鏈路本地地址,它只能從給定的子網內訪問。一個例子是Amazon Time Sync Service,它可用于鏈接本地 IP 上的AWS EC2實例169.254.169.123。如果您的 EC2 實例位于Virtual Private Cloud?(VPC) 中,那么您不需要 Internet 連接來告訴您的實例現在是什么時間。塊 169.254.0.0/16 保留用于鏈路本地地址:

      >>>

      >>> timesync_addr = IPv4Address("169.254.169.123") >>> timesync_addr.is_link_local True

      在上面,您可以看到確認這10.243.156.214是一個私有地址的一種方法是測試它是否位于該10.0.0.0/8范圍內。但是 Python 的ipaddress模塊也提供了一組用于測試地址是否為特殊類型的屬性:

      >>> IPv4Address("10.243.156.214").is_private True >>> IPv4Address("127.0.0.1").is_loopback True >>> [i for i in dir(IPv4Address) if i.startswith("is_")] # "is_X" properties ['is_global', 'is_link_local', 'is_loopback', 'is_multicast', 'is_private', 'is_reserved', 'is_unspecified']

      .is_private不過,需要注意的一件事是,它使用了比上表中顯示的三個 IANA 范圍更廣泛的專用網絡定義。Python 的ipaddress模塊還包含為專用網絡分配的其他地址:

      0.0.0.0/8用于“此網絡上的此主機”。

      127.0.0.0/8用于環回地址。

      169.254.0.0/16?用于如上所述的鏈路本地地址。

      198.18.0.0/15用于對網絡性能進行基準測試。

      這不是一個詳盡的列表,但它涵蓋了最常見的情況。

      ipaddress引擎蓋下的Python模塊

      除了其文檔化的 API 之外,模塊及其類的CPython 源代碼還ipaddressIPv4Address提供了一些關于如何使用稱為組合的模式為您自己的代碼提供慣用 API 的深刻見解。

      組合的核心作用

      該ipaddress模塊利用了一種稱為組合的面向對象模式。它的IPv4Address類是一個復合的,它包裝了一個普通的 Python 整數。畢竟,IP 地址基本上是整數。

      注意:公平地說,該ipaddress模塊還使用了健康劑量的繼承,主要是為了減少代碼重復。

      每個IPv4Address實例都有一個準私有._ip屬性,它本身就是一個int.?該類的許多其他屬性和方法都由該屬性的值驅動:

      >>>

      >>> addr = IPv4Address("220.14.9.37") >>> addr._ip 3691907365

      該._ip屬性實際上是負責生產int(addr).?調用鏈是int(my_addr)調用my_addr.__int__(),它IPv4Address實現為my_addr._ip:

      如果您向CPython開發人員詢問了這一點,那么他們可能會告訴您這._ip是一個實現細節。雖然 Python 中沒有真正私有的,但前導下劃線表示它._ip是準私有的,不是公共ipaddressAPI 的一部分,如有更改,恕不另行通知。這就是為什么用 提取底層整數更穩定的原因int(addr)。

      盡管如此,正是底層._ip賦予了IPv4Address和IPv4Network類它們的魔力。

      擴展?IPv4Address

      您可以._ip通過擴展IPv4 地址類來展示底層整數的強大功能:

      from ipaddress import IPv4Address class MyIPv4(IPv4Address): def __and__(self, other: IPv4Address): if not isinstance(other, (int, IPv4Address)): raise NotImplementedError return self.__class__(int(self) & int(other))

      添加.__and__()允許您使用二元 AND (?&) 運算符。現在您可以直接將網絡掩碼應用于主機 IP:

      >>>

      >>> addr = MyIPv4("100.127.40.32") >>> mask = MyIPv4("255.192.0.0") # A /10 prefix >>> addr & mask MyIPv4('100.64.0.0') >>> addr & 0xffc00000 # Hex literal for 255.192.0.0 MyIPv4('100.64.0.0')

      上面,.__and__()允許您使用 anotherIPv4Address或 anint直接作為掩碼。因為MyIPv4是 的子類IPv4Address,在這種情況下isinstance()檢查將返回True。

      除了運算符重載之外,您還可以添加全新的屬性:

      import re 2from ipaddress import IPv4Address 3 4class MyIPv4(IPv4Address): 5 @property 6 def binary_repr(self, sep=".") -> str: 7 """Represent IPv4 as 4 blocks of 8 bits.""" 8 return sep.join(f"{i:08b}" for i in self.packed) 9 10 @classmethod 11 def from_binary_repr(cls, binary_repr: str): 12 """Construct IPv4 from binary representation.""" 13 # Remove anything that's not a 0 or 1 14 i = int(re.sub(r"[^01]", "", binary_repr), 2) 15 return cls(i)

      在.binary_repr(第 8 行)中, using.packed將 IP 地址轉換為字節數組,然后將其格式化為其二進制形式的字符串表示形式。

      在 中.from_binary_repr,int(re.sub(r"[^01]", "", binary_repr), 2)對第 14 行的調用有兩個部分:

      它從輸入字符串中刪除除 0 和 1 之外的任何內容。

      它解析結果,假設基數為 2,int(, 2).

      使用.binary_repr()和.from_binary_repr()允許您以str二進制表示法轉換為1 和 0 的a 并從中構造:

      >>> MyIPv4("220.14.9.37").binary_repr '11011100.00001110.00001001.00100101' >>> MyIPv4("255.255.0.0").binary_repr # A /16 netmask '11111111.11111111.00000000.00000000' >>> MyIPv4.from_binary_repr("11011100 00001110 00001001 00100101") MyIPv4('220.14.9.37')

      這些只是展示如何利用 IP-as-integer 模式可以幫助您IPv4Address使用少量附加代碼擴展功能的幾種方法。

      結論

      在本教程中,您了解了 Python 的ipaddress模塊如何允許您使用常見的 Python 構造來處理 IP 地址和網絡。

      以下是您可以帶走的一些要點:

      IP 地址基本上是一個integer,這是如何使用地址進行手動算術以及如何ipaddress使用組合設計Python 類的基礎。

      該ipaddress模塊利用運算符重載來推斷地址和網絡之間的關系。

      該ipaddress模塊使用組合,您可以根據需要擴展該功能以添加行為。

      與往常一樣,如果您想深入了解,那么閱讀模塊源代碼是一個很好的方法。

      進一步閱讀

      以下是一些深入的資源,您可以查看這些資源以了解有關該ipaddress模塊的更多信息:

      Pythonipaddress模塊文檔

      ipaddress模塊簡介

      Python 的“ipaddress”模塊概述

      Python TCP/IP 網絡

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:wps表格里面怎么打勾(wps怎樣在表格里打勾)
      下一篇:定制家居門店軟件 - 為你的家居定制添上一抹智能
      相關文章
      亚洲欧美日韩中文无线码| 久久久久亚洲精品美女| 亚洲熟妇av一区| 国产成A人亚洲精V品无码性色| 亚洲大尺码专区影院| 亚洲美女人黄网成人女| 99久久精品国产亚洲| 亚洲成年轻人电影网站www| 精品国产亚洲一区二区三区| 国产成人综合亚洲亚洲国产第一页 | 亚洲AV无码AV吞精久久| 久久久久久亚洲av无码蜜芽| 爱爱帝国亚洲一区二区三区| 亚洲国产成人久久综合野外| 亚洲精品无码AV中文字幕电影网站| 亚洲区小说区图片区| 国产亚洲情侣一区二区无| 国产专区一va亚洲v天堂| 亚洲中文字幕无码一区二区三区| 国产亚洲精品影视在线产品 | 亚洲乱码一二三四区乱码| 亚洲图片激情小说| 亚洲中文字幕日本无线码| 亚洲熟妇AV日韩熟妇在线| 亚洲大码熟女在线观看| 亚洲成av人片一区二区三区| 精品亚洲一区二区三区在线观看 | 亚洲国产超清无码专区| 亚洲伊人久久大香线蕉AV| 亚洲精品色播一区二区| 国产亚洲精品美女久久久久久下载| 亚洲国产免费综合| 亚洲色WWW成人永久网址| 亚洲尹人九九大色香蕉网站| 亚洲国产综合精品| 亚洲精品无码专区在线| 亚洲欧洲精品成人久久曰影片 | 亚洲AV成人影视在线观看| 色九月亚洲综合网| 亚洲日韩欧洲无码av夜夜摸| 亚洲AV人无码激艳猛片|