我的脚本有一个小问题,我需要将 'xxx.xxx.xxx.xxx' 形式的 ip 转换为整数表示形式,然后从该形式返回。
def iptoint(ip):
return int(socket.inet_aton(ip).encode('hex'),16)
def inttoip(ip):
return socket.inet_ntoa(hex(ip)[2:].decode('hex'))
In [65]: inttoip(iptoint('192.168.1.1'))
Out[65]: '192.168.1.1'
In [66]: inttoip(iptoint('4.1.75.131'))
---------------------------------------------------------------------------
error Traceback (most recent call last)
/home/thc/<ipython console> in <module>()
/home/thc/<ipython console> in inttoip(ip)
error: packed IP wrong length for inet_ntoa`
有人知道如何解决吗?
#!/usr/bin/env python
import socket
import struct
def ip2int(addr):
return struct.unpack("!I", socket.inet_aton(addr))[0]
def int2ip(addr):
return socket.inet_ntoa(struct.pack("!I", addr))
print(int2ip(0xc0a80164)) # 192.168.1.100
print(ip2int('10.0.0.1')) # 167772161
Python 3 有 ipaddress 模块,其功能非常简单:
int(ipaddress.IPv4Address("192.168.0.1"))
str(ipaddress.IPv4Address(3232235521))
在纯Python中不使用额外的模块
def IP2Int(ip):
o = map(int, ip.split('.'))
res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3]
return res
def Int2IP(ipnum):
o1 = int(ipnum / 16777216) % 256
o2 = int(ipnum / 65536) % 256
o3 = int(ipnum / 256) % 256
o4 = int(ipnum) % 256
return '%(o1)s.%(o2)s.%(o3)s.%(o4)s' % locals()
# Example
print('192.168.0.1 -> %s' % IP2Int('192.168.0.1'))
print('3232235521 -> %s' % Int2IP(3232235521))
结果:
192.168.0.1 -> 3232235521
3232235521 -> 192.168.0.1
您丢失了左零填充,这会破坏字符串的解码。
这是一个工作函数:
def inttoip(ip):
return socket.inet_ntoa(hex(ip)[2:].zfill(8).decode('hex'))
以下是最快和最简单的(据我所知) IPv4 和 IPv6 转换器:
try:
_str = socket.inet_pton(socket.AF_INET, val)
except socket.error:
raise ValueError
return struct.unpack('!I', _str)[0]
-------------------------------------------------
return socket.inet_ntop(socket.AF_INET, struct.pack('!I', n))
-------------------------------------------------
try:
_str = socket.inet_pton(socket.AF_INET6, val)
except socket.error:
raise ValueError
a, b = struct.unpack('!2Q', _str)
return (a << 64) | b
-------------------------------------------------
a = n >> 64
b = n & ((1 << 64) - 1)
return socket.inet_ntop(socket.AF_INET6, struct.pack('!2Q', a, b))
不使用
inet_ntop()
和 struct
模块的 Python 代码无论它在做什么,都比这慢一个数量级。
一行
reduce(lambda out, x: (out << 8) + int(x), '127.0.0.1'.split('.'), 0)
Python3 oneliner(基于 Thomas Webber 的 Python2 答案):
sum([int(x) << 8*i for i,x in enumerate(reversed(ip.split('.')))])
左移比 pow() 快得多。
无需使用任何库即可完成。
def iptoint(ip):
h=list(map(int,ip.split(".")))
return (h[0]<<24)+(h[1]<<16)+(h[2]<<8)+(h[3]<<0)
def inttoip(ip):
return ".".join(map(str,[((ip>>24)&0xff),((ip>>16)&0xff),((ip>>8)&0xff),((ip>>0)&0xff)]))
iptoint("8.8.8.8") # 134744072
inttoip(134744072) # 8.8.8.8
ip2int = lambda ip: reduce(lambda a,b: long(a)*256 + long(b), ip.split('.'))
ip2int('192.168.1.1')
#output
3232235777L
# from int to ip
int2ip = lambda num: '.'.join( [ str((num >> 8*i) % 256) for i in [3,2,1,0] ])
int2ip(3232235777L)
#output
'192.168.1.1'
我给出一个更容易理解的方式:
ip 到 int
def str_ip2_int(s_ip='192.168.1.100'):
lst = [int(item) for item in s_ip.split('.')]
print lst
# [192, 168, 1, 100]
int_ip = lst[3] | lst[2] << 8 | lst[1] << 16 | lst[0] << 24
return int_ip # 3232235876
以上:
lst = [int(item) for item in s_ip.split('.')]
相当于:
lst = map(int, s_ip.split('.'))
还有:
int_ip = lst[3] | lst[2] << 8 | lst[1] << 16 | lst[0] << 24
相当于:
int_ip = lst[3] + (lst[2] << 8) + (lst[1] << 16) + (lst[0] << 24)
int_ip = lst[3] + lst[2] * pow(2, 8) + lst[1] * pow(2, 16) + lst[0] * pow(2, 24)
int转ip:
def int_ip2str(int_ip=3232235876):
a0 = str(int_ip & 0xff)
a1 = str((int_ip & 0xff00) >> 8)
a2 = str((int_ip & 0xff0000) >> 16)
a3 = str((int_ip & 0xff000000) >> 24)
return ".".join([a3, a2, a1, a0])
或:
def int_ip2str(int_ip=3232235876):
lst = []
for i in xrange(4):
shift_n = 8 * i
lst.insert(0, str((int_ip >> shift_n) & 0xff))
return ".".join(lst)
我的方法是直接查看数字的存储方式,而不是显示方式,并将其从显示格式操作为存储格式,反之亦然。
所以,从 IP 地址到整数:
def convertIpToInt(ip):
return sum([int(ipField) << 8*index for index, ipField in enumerate(reversed(ip.split('.')))])
这会评估每个字段,并将其移动到正确的偏移量,然后将它们全部相加,巧妙地将 IP 地址的显示转换为其数值。
相反方向,从 int 到 IP 地址:
def convertIntToIp(ipInt):
return '.'.join([str(int(ipHexField, 16)) for ipHexField in (map(''.join, zip(*[iter(str(hex(ipInt))[2:].zfill(8))]*2)))])
首先将数字表示形式转换为其十六进制字符串表示形式,可以将其作为序列进行操作,从而更容易分解。然后,通过将 ''.join 映射到对的元组上来提取对,该对的元组是通过将两个引用的列表压缩到 IP 字符串的迭代器而提供的(请参阅 zip(*[iter(s)]*n) 如何工作? ),这些对依次从十六进制字符串表示形式转换为整型字符串表示形式,并用 '.' 连接。
def ip2int(ip):
"""
Convert IP string to integer
:param ip: IP string
:return: IP integer
"""
return reduce(lambda x, y: x * 256 + y, map(int, ip.split('.')))
def int2ip(num):
"""
Convert IP integer to string
:param num: IP integer
:return: IP string
"""
return '.'.join(map(lambda x: str(num // 256 ** x % 256), range(3, -1, -1)))
现代 Python(>= 3.11)也有很棒的
int.from_bytes
和 int.to_bytes
方法:
>>> import socket
>>> socket.inet_aton('4.1.75.131')
b'\x04\x01K\x83'
>>> int.from_bytes(socket.inet_aton('4.1.75.131'))
67193731
>>> int.from_bytes(socket.inet_aton('10.0.0.1'))
167772161
>>>
# int2ip
>>> socket.inet_ntoa(167772161 .to_bytes(4))
'10.0.0.1'