将IP地址字符串转换为数字及其反向转换

61

我该如何使用Python将一个str类型的IP地址转换为十进制数或反过来呢?

例如,对于IP地址186.99.109.000 <type'str'>,我想要一个易于存储和检索的十进制或二进制形式。


http://code.google.com/p/ipaddr-py/ - DrTyrsa
4
@PeterWood,现在我只是谷歌搜索了一下,第一个结果就是这个答案 xD。 - markcial
11个回答

109

将IP字符串转换为长整型:

import socket, struct

def ip2long(ip):
    """
    Convert an IP string to long
    """
    packedIP = socket.inet_aton(ip)
    return struct.unpack("!L", packedIP)[0]

反之亦然:

>>> socket.inet_ntoa(struct.pack('!L', 2130706433))
'127.0.0.1'

37
我喜欢Python文档中的这句话:“对于那些声称记不住网络字节顺序是大端还是小端的可怜人,可以使用 '!' 这个格式。” - Not_a_Golfer

63

以下是截至2017-06的所有选项概述。所有模块均为标准库的一部分,或可通过 pip install 进行安装。

ipaddress 模块

ipaddress 模块(文档)自 v3.3 版本起已成为标准库的一部分,但也可作为外部模块供 python v2.6、v2.7 使用。

>>> import ipaddress
>>> int(ipaddress.ip_address('1.2.3.4'))
16909060
>>> str(ipaddress.ip_address(16909060))
'1.2.3.4'
>>> int(ipaddress.ip_address(u'1000:2000:3000:4000:5000:6000:7000:8000'))
21268296984521553528558659310639415296L
>>> str(ipaddress.ip_address(21268296984521553528558659310639415296L))
u'1000:2000:3000:4000:5000:6000:7000:8000'

无需导入模块(仅限IPv4)

无需导入任何模块,但仅适用于IPv4且代码比其他选项更长。

>>> ipstr = '1.2.3.4'
>>> parts = ipstr.split('.')
>>> (int(parts[0]) << 24) + (int(parts[1]) << 16) + \
          (int(parts[2]) << 8) + int(parts[3])
16909060
>>> ipint = 16909060
>>> '.'.join([str(ipint >> (i << 3) & 0xFF)
          for i in range(4)[::-1]])
'1.2.3.4'

模块 netaddr

netaddr 是一个外部模块,但自 Python 2.5(文档)以来非常稳定且可用。

>>> import netaddr
>>> int(netaddr.IPAddress('1.2.3.4'))
16909060
>>> str(netaddr.IPAddress(16909060))
'1.2.3.4'
>>> int(netaddr.IPAddress(u'1000:2000:3000:4000:5000:6000:7000:8000'))
21268296984521553528558659310639415296L
>>> str(netaddr.IPAddress(21268296984521553528558659310639415296L))
'1000:2000:3000:4000:5000:6000:7000:8000'

模块套接字和结构体(仅适用于IPv4)

这两个模块都是标准库的一部分,代码很短,有些晦涩难懂,只支持IPv4。

>>> import socket, struct
>>> ipstr = '1.2.3.4'
>>> struct.unpack("!L", socket.inet_aton(ipstr))[0]
16909060
>>> ipint=16909060
>>> socket.inet_ntoa(struct.pack('!L', ipint))
'1.2.3.4'

1
不需要使用像2 ** 16这样的内容,只需改用<< 16即可。 - interestinglythere
1
感谢您的提示,interestinglythere。我喜欢这种表示法(它让我想起了我的第一个6502汇编程序)。 - ndemou
用户brisebom试图将此评论发布为答案:“这里是大多数@ndemou答案示例的简单基准测试。如果您已经使用ipaddress模块进行地址处理,则IP int已经预先计算,因此它是最快的方法。否则,socket / struct是相当快的方法。 https://ideone.com/cZU9Ar” - Artjom B.
一个善良的人在这里进行了一些基准测试 https://ideone.com/cZU9Ar -- 感谢 @brisebom 和 artjom-b 告诉我们(我只是在这里重复,因为Artjom评论中的链接已经损坏) - ndemou
1
str(ipaddress.ip_address(16909060)) 是将整数转换为字符串的更简单的方式。 - Bob Stein

30

使用netaddr模块中的IPAddress类。

将ipv4 str转换为int

print int(netaddr.IPAddress('192.168.4.54'))
# OUTPUT: 3232236598

将ipv4 int转换为str

print str(netaddr.IPAddress(3232236598))
# OUTPUT: 192.168.4.54

将IPv6str转换为int

print int(netaddr.IPAddress('2001:0db8:0000:0000:0000:ff00:0042:8329'))
# OUTPUT: 42540766411282592856904265327123268393

将ipv6 int转化为str

print str(netaddr.IPAddress(42540766411282592856904265327123268393))
# OUTPUT: 2001:db8::ff00:42:8329

非常好,但将输出放在输入之前会让我感到困惑。 - ndemou

7
自Python 3.3以来,就有了ipaddress模块,可以完成这项工作和其他工作:https://docs.python.org/3/library/ipaddress.html。Python 2.x的后移版本也可以在PyPI上获得。
示例用法:
import ipaddress

ip_in_int = int(ipaddress.ip_address('192.168.1.1'))
ip_in_hex = hex(ipaddress.ip_address('192.168.1.1'))

2
对于hex(ipaddress.ip_address('192.168.1.1')),出现了错误。'IPv4Address'对象无法解释为整数。似乎要使用hex(int(...))。了解新的ipaddress模块是很好的。 - Peng Zhang
最后一行应该是 ipaddress.ip_address(3232235777).__str__()。这实际上返回了 '192.168.1.1',这就是问题所要求的。 - ndemou

6

以下是一句话回答:

import socket, struct

def ip2long_1(ip):
    return struct.unpack("!L", socket.inet_aton(ip))[0]

def ip2long_2(ip):
    return long("".join(["{0:08b}".format(int(num)) for num in ip.split('.')]), 2)

def ip2long_3(ip):
    return long("".join(["{0:08b}".format(num) for num in map(int, ip.split('.'))]), 2)

执行时间:

ip2long_1 => 0.0527065660363234(最快)
ip2long_2 => 0.577211893924598
ip2long_3 => 0.5552745958088666


5

不需要导入任何模块的一行解决方案:

ip2int = lambda ip: reduce(lambda a, b: (a << 8) + b, map(int, ip.split('.')), 0)
int2ip = lambda n: '.'.join([str(n >> (i << 3) & 0xFF) for i in range(0, 4)[::-1]])

例子:

In [3]: ip2int('121.248.220.85')
Out[3]: 2046352469

In [4]: int2ip(2046352469)
Out[4]: '121.248.220.85'

5

将IP地址转换为整数:

python -c "print sum( [int(i)*2**(8*j) for  i,j in zip( '10.20.30.40'.split('.'), [3,2,1,0]) ] )"

将整数转换为IP地址:

python -c "print '.'.join( [ str((169090600 >> 8*i) % 256)  for i in [3,2,1,0] ])" 

1
def ip2Hex(ip = None):
    '''Returns IP in Int format from Octet form'''
    #verifyFormat(ip)
    digits=ip.split('.')
    numericIp=0
    count=0
    for num in reversed(digits):
        print "%d " % int(num)
        numericIp += int(num) * 256 **(count)
        count +=1
    print "Numeric IP:",numericIp
    print "Numeric IP Hex:",hex(numericIp)

ip2Hex('192.168.192.14')
ip2Hex('1.1.1.1')
ip2Hex('1.0.0.0')

0
如果您的IP地址在DataFrame中,您可以使用库DataPrep中的函数clean_ip。使用pip install dataprep安装DataPrep。
from dataprep.clean import clean_ip
df = pd.DataFrame({"ip": ["186.99.109.000", "127.0.0.1", "1.2.3.4"]})

要将其转换为十进制格式,请将参数output_format设置为"integer"

df2 = clean_ip(df, "ip", output_format="integer")
# print(df2)
               ip    ip_clean
0  186.99.109.000  3127078144
1       127.0.0.1  2130706433
2         1.2.3.4    16909060

要将其转换为二进制格式,请将参数output_format设置为"binary"
df2 = clean_ip(df, "ip", output_format="binary")
# print(df2)
               ip                          ip_clean
0  186.99.109.000  10111010011000110110110100000000
1       127.0.0.1  01111111000000000000000000000001
2         1.2.3.4  00000001000000100000001100000100

要转换回IPv4,请将参数output_format设置为"compressed"

df = pd.DataFrame({"ip": [3127078144, 2130706433, 16909060]})
df2 = clean_ip(df, "ip", output_format="compressed")
# print(df2)
           ip      ip_clean
0  3127078144  186.99.109.0
1  2130706433     127.0.0.1
2    16909060       1.2.3.4

0
你必须先将包含 IP 地址的字符串转换为字节或一串字节,然后开始通信。 根据下面的代码,您的错误将得到解决。 确保您的代码总体上正确运行。
string = '192.168.1.102'
new_string = bytearray(string,"ascii")
ip_receiver = new_string
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(text.encode(), (ip_receiver, 5252))

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