网上找了些python做IP地址转换的方法,python2.5可以正常使用,

蛋python2.6以上经常会报错OverflowError: can't convert negative number to unsigned long

 

仔细看了下,应该是因为socket.htonl做了限制,不再支持负数转换了

 

所以转换时需要先把负数转换成long,再做地址转换

 


import socket
import struct
def str2uint(str):
	# 得到始终是正数
	return socket.ntohl(struct.unpack("I",socket.inet_aton(str))[0])
	
def str2int(str):
	uint = socket.ntohl(struct.unpack("I",socket.inet_aton(str))[0])
	# 先得到负数,再转换一下
	return struct.unpack("i", struct.pack('I', uint))[0]
def num2str(ip):
	if ip < 0:
		ip = struct.unpack("I", struct.pack('i', ip))[0]
	return socket.inet_ntoa(struct.pack('I',socket.htonl(ip)))






测试结果:

print str2uint("10.7.11.213")
print str2int("10.7.11.213")
print num2str(168233941)


Python IP地址 socket.inet_ntoa  



def Ip2Int(ip): 
 
    import struct,socket

     return struct.unpack("!I",socket.inet_aton(ip))[0]



此函数从’192.168.1.235’ 可以转换为数字’3120670912’,此数字为网络字节序

def Int2Ip(i):

     import socket,struct

     return socket.inet_ntoa(struct.pack("!I",i))

  此函数从网络字节序的数字’’转换为ip


>>>
 socket.inet_ntoa(struct.pack('I',socket.htonl(16909060)))
 '1.2.3.4'

 />>> socket.ntohl(struct.unpack("I",socket.inet_aton('1.2.3.4'))[0])
 16909060


再加几个:

>>> struct.unpack("I",socket.inet_aton('1.2.3.4'))  
 (67305985L,)

>>> socket.ntohl(67305985)
 16909060

 />>> socket.htonl(16909060)
 67305985

 />>> struct.unpack('i',socket.inet_aton('1.2.3.4'))
 (67305985,)

 />>> struct.pack('i',16909060)  
 '\x04\x03\x02\x01'

 />>> struct.pack('i',67305985)
 '\x01\x02\x03\x04'

 />>> socket.inet_ntoa(struct.pack('I',socket.ntohl(16909060)))    
 '1.2.3.4'

 />>> socket.htonl(struct.unpack("I",socket.inet_aton('1.2.3.4'))[0])
 16909060


(1). inet_aton 将ip地址的4段地址分别进行2进制转化,输出用16进制表示:
1.2.3.4 ——inet_aton——> 0000 0001,0000 0010,0000 0011,0000 0100

(2).unpack的处理是按16进制(4bit)将2进制字符,从后向前读入的,低位入,处理成:
00000100 00000011 00000010 00000001 
也就是 4 3 2 1 

pack也一样,从后向前读入字符,所以——
用16进制表示的1 2 3 4(16909060)打包成 4 3 2 1 的顺序;
用16进制表示的4 3 2 1(67305985)打包成 1 2 3 4 的顺序;
(3) ntohl, htonl 表示的是网络地址和主机地址之间的转换(network byte <==> host byte)
由于unpack/pack的解/打包的颠倒顺序,必须通过htonl 或者 ntohl 进行处理。

(4) network byte, host byte
这 2个名词折腾半天,host byte 由于处理器的方式不同
little-endian或者big-endian,将ip地址转换的最终输出是不一样的,

big-endian: 最高位在左边(内存存储空间的最低位)
little-endian: 最高位在右边(内存存储空间的最低位)

由于x86本身的处理属于little-endian,所以上述应该按照标准的network
byte 进行处理,这样可避免cpu造成的不同:

socket.htonl(struct.unpack("I",socket.inet_aton('1.2.3.4'))[0])

 socket.inet_ntoa(struct.pack('I',socket.htonl(16909060)))


###############################################################################
(1个64位amd+32位windows, 1个32位intel+linux,
出来的数值是一样的:

/>>>
 socket.ntohl(struct.unpack("I",socket.inet_aton('220.194.61.32'))[0])
 -591250144

 />>> socket.inet_ntoa(struct.pack('I',socket.htonl(-591250144)))
 '220.194.61.32'



但是64位amd+64位linux,是这样:

/>>> socket.ntohl(struct.unpack("I",socket.inet_aton('220.194.61.32'))[0])
 3703717152

 />>> socket.inet_ntoa(struct.pack('I',socket.htonl(-591250144)))
 '220.194.61.32'

 />>>
 socket.inet_ntoa(struct.pack('I',socket.htonl(3703717152)))         
 '220.194.61.32'

 unpack/pack和cpu,os无关;



socket.ntohl/htonl的输出结果int型
对32 os,处理成signed 类型,首位1被处理成负数;
对 64位 os,则是unsigned类型;

(5)mysql里面的函数是inet_aton,
inet_ntoa 和python的socket不同,直接实现ip string到network byte的转换,python里面只能实现ip地址到network byte的2进制转换:

mysql> select inet_aton('1.2.3.4');
 -> 16909060



mysql> select inet_ntoa(16909060);
 -> 1.2.3.4

http://shanchao7932297.blog.163.com/blog/static/136362420101010114656305/