在Python中将IP字符串转换为整数,以及反向转换

62

我有一个小问题需要解决,需要将形式为'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`

有人知道如何修复这个问题吗?


2
在我的Python 2.6.6中根本不起作用:inttoip引发了一个TypeError: Odd-length string错误。 - Ilkka
@Ilkka 使用 socket.inet_ntoa(hex(ip)[2:].decode('hex')) 将整数转换为IP地址 - Maksym Polshcha
12个回答

115
#!/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

这需要 import struct - StockB
1
比起ipaddress,速度快3倍。 - 0script0

98

Python 3拥有ipaddress模块,其中包含非常简单的转换功能:

int(ipaddress.IPv4Address("192.168.0.1"))
str(ipaddress.IPv4Address(3232235521))

4
应该将此置为最佳答案。Python 2也有这个模块,但不是内置的。 - Smit Johnth
1
这个模块非常慢。 - Jiulin Teng
1
我刚刚在50个IP地址上运行了这个脚本,当我没有运行额外的转换和再次转换时,与我的原始脚本相比没有明显的差异... 对我来说似乎足够快。 - c7borg

28

使用纯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

我意识到这篇文章相当古老,但你也可以使用 pow 函数:res = (o[0] * pow(256, 3)) + (o[1] * pow(256, 2)) + (o[2] * 256) + o[3] - Renier
1
伙计,'%(o1)s.%(o2)s.%(o3)s.%(o4)s' % locals() 是非常糟糕的风格。 - Smit Johnth
@SmitJohnth 感谢您提供另一种解决方案..., 在这里,新的样式可以是 f'{o1}.{o2}.{o3}.{o4}' - Bruno Adelé

12

你失去了左侧的零填充,这会破坏对字符串的解码。

这里是一个可行的函数:

def inttoip(ip):
    return socket.inet_ntoa(hex(ip)[2:].zfill(8).decode('hex'))

是的,你也将 [2:-1] 切片修复为 [2:],这正是我上面评论过的错误原因。 - Ilkka
1
如果ip是LONG类型,字符串末尾会有一个'L'字符。请将hex(ip)替换为hex(int(ip))或在[2:]后添加.rstrip('L') - johnny

8
以下是我所知道的最快和最简单的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))

如果Python代码没有使用inet_ntop()struct模块,那么无论它做什么,都比使用这些模块慢一个数量级。


socket.inet_pton和inet_ntop仅在Unix上可用。 - johnny

6

一行

reduce(lambda out, x: (out << 8) + int(x), '127.0.0.1'.split('.'), 0)

比起乘法,左移位运算远比它更高效/快速。 - Galland

6

Python3的一行代码(基于Thomas Webber的Python2答案):

sum([int(x) << 8*i for i,x in enumerate(reversed(ip.split('.')))])

左移操作比pow()函数快得多。


5

可以不使用任何库来实现。

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

1
def iptoint(ip): h = list(map(int, ip.split("."))) return (h[0] << 24) + (h[1] << 16) + (h[2] << 8) + (h[3] << 0) - Ken

3

我使用了以下内容:

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'

1
将IP地址转换为整数。
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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接