ip地址到数字之间的转换
才疏啊,google后找到将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地址转换的最终输出是不一样的,参考(http://www.informit.com/articles/article.aspx?p=169505&seqNum=4 )
(http://www.netrino.com/Embedded-Systems/How-To/Big-Endian-Little-Endian)
big-endian: 最高位在左边(内存存储空间的最低位)
little-endian: 最高位在右边(内存存储空间的最低位)
i386-unknown-freebsd4.8: little-endian
powerpc-apple-darwin6.6: big-endian
sparc64-unknown-freebsd5.1: big-endian
powerpc-ibm-aix5.1.0.0: big-endian
hppa1.1-hp-hpux11.11: big-endian
i586-pc-linux-gnu: little-endian
sparc-sun-solaris2.9: big-endian
而为了统一这种传输标准(打个补丁,再创造一个名词函数),又有network byte,这个其实就是标准的big-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类型;
(晕了半天,那个值才明白是位数,和cpu不相干)
###############################################################################
(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