https://docs.python.org/3.7/howto/ipaddress.html
author: Peter Moody, Nick Coghlan
An introduction to the ipaddress module
本文简单介绍了python自带的 ipaddress
模块,只涉及了模块的基础部分,更多函数介绍,还是要参考模块的手册.
ipaddress
模块是面向对象的。使用前先要创建相应对象。可以使用字符串或者整数来创建如下三种IP地址对象
注:此库支持ipv4和ipv6
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')
也可以使用正整数来创建地址,默认的,小于2^32认为是IPV4,大于则是IPv6地址:
>>> ipaddress.ip_address(3221225985)
IPv4Address('192.0.2.1')
>>> ipaddress.ip_address(42540766411282592856903984951653826561)
IPv6Address('2001:db8::1')
当然也可以用派生类IPv4Address/IPv6Address强制创建ipv4/ipv6地址:
>>> ipaddress.ip_address(1)
IPv4Address('0.0.0.1')
>>> ipaddress.IPv4Address(1)
IPv4Address('0.0.0.1')
>>> ipaddress.IPv6Address(1)
IPv6Address('::1')
ip/mask表示一个网段,可以使用ip_network
创建IPv4/IPv6:
>>> 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
就不是一个有效的网段,初始化时程序会抛出一个 ValueError
异常. 可以设置参数strict=False
来自动的把主机地址置0:
>>> 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')
如果使用一个整数来创建网段,则认为这个网段为单ip网段,掩码为32/128:
>>> ipaddress.ip_network(3221225984)
IPv4Network('192.0.2.0/32')
>>> ipaddress.ip_network(42540766411282592856903984951653826560)
IPv6Network('2001:db8::/128')
As with addresses, creation of a particular kind of network can be forced by calling the class constructor directly instead of using the factory function.
通常用cidr表示某个网络中的某台主机,比如192.0.2.1/24
表示192.0.2.0/24
网络中的主机192.0.2.1
。ipaddress
模块提供了类接口ip_interface
来定义一个主机cidr地址
>>> 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')
用上面接口定义了IPv(4|6)(Address|Network|Interface)对象,可以调用下面的成员函数来获取对象的一些属性.
>>> 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
netmask/hostmask
来获取网络/主机掩码:>>> 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地址,依然提供这两个方法,只是不做处理,原值返回,这样代码可以不区分的调用而不会产生异常
一个网段可以通过索引获取主机地址:
>>> net4 = ipaddress.ip_network('192.0.2.0/24')
>>> 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')
可以判断某个ip是否在一个网段
# 参考代码
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
注:如果对比不是IPv4和IPv4或者和IPv6地址,会抛出
TypeError
异常
>>> addr4 = ipaddress.ip_address('192.0.2.1')
>>> str(addr4)
'192.0.2.1'
>>> int(addr4)
3221225985
如果使用类工厂来创建IPv4/IPv6对象时,遇到错误,只会抛出 ValueError
异常,因为类工厂不知道要创建哪种类,所以错误提示不是特别明确。如果想得到更多错误信息,可以使用原始IPv4/IPv6类来创建对象,这样会抛出ValueError
的子类,比如ipaddress.AddressValueError
, ipaddress.NetmaskValueError
来通知用户具体错误信息
The error messages are significantly more detailed when using the class constructors directly. For example:
>>> 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)