python getaddrinfo 函数
现在python中用到的关于地址查询的函数几乎都可以用getaddrinfo。 也就是说,如果你要想做一些与地址查询,主机名ip转换的操作,都可以用这个函数,下面看一下这个函数。
首先,我们可以用getaddrinfo查询到想访问主机的ip地址和端口号
>>> import socket >>> from pprint import pprint >>> infolist=socket.getaddrinfo('baidu.com','www') >>> pprint(infolist) [(2, 1, 6, '', ('220.181.111.86', 80)), (2, 2, 17, '', ('220.181.111.86', 80)), (2, 1, 6, '', ('123.125.114.144', 80)), (2, 2, 17, '', ('123.125.114.144', 80)), (2, 1, 6, '', ('220.181.111.85', 80)), (2, 2, 17, '', ('220.181.111.85', 80))]
可以看到我们提供了主机名 baidu.com 和 想要访问的端口号 www。 getaddrinfo就会为我们返回可以用来访问的地址。从返回的数据看出有多个地址可以访问www.baidu.com。
取其中任意一个地址分析一下:
(2, 1, 6, '', ('220.181.111.86', 80))
这个地址可以简称为ftpca。f是family,t是type,p是protocol,c是cononnical name,a是address。这个ftpca的 前三位可以用来构造一个socket
2 是 AF_INET
1 是 SOCK_STREAM
6 是 IPPROTOTCP
这些都是可以用来构建一个socket的。 比如接下来的代码。
>>> ftpca=infolist[0] >>> ftpca[0:3] (2, 1, 6) >>> s=socket.socket(*ftpca[0:3]) >>> ftpca[4] ('220.181.111.86', 80) >>> s.connect(ftpca[4])
首先,我们把地址列表中的第一个地址单独获得赋给变量ftpca。 然后用ftpca[0:3]就是前三位构建了一个socket。在构建的时候使用了*是说明传入的参数不是一个list而是单独的个体。这是socket constructor的特性。而后面我们用s.connect调用地址去连接并且连接成功。这里注意的是没有使用*,说明connect函数的参数可以是一个 list 。
其次,可以用getaddrinfo的一个地方就是,我们可以用该函数获取我们需要bind的信息。比如你的程序要把socket bind到当前的机器上。bind所需要的信息就可以用getaddrinfo获取。
>>> getaddrinfo(None,'ssh',0,socket.SOCK_STREAM,0,socket.AI_PASSIVE) [(2, 1, 6, '', ('0.0.0.0', 22)), (10, 1, 6, '', ('::', 22, 0, 0))]
先解释一下参数的意思。
None 是传入主机名的地方,这里用none就是说当前主机。
ssh 是端口号。
0 默认稍后解释是什么参数。
socket.SOCK_STREAM是tcp。getaddrinfo这个函数返回的值是ftpca。tp就是说返回的值里包含了scoket type。这里的socket.SOCK_STREAM指定了type是TCP
0 more稍后解释是什么参数。
socket.AI_PASSIVE要结合前面的None来理解。我们用了none + socket.AI_PASSIVE这两个参数。这样函数把当前机器所有的地址都返回了。可是如果你只想返回当前机器的某个ip。比如当前机器的loopback interface的信息,你就可以把none 换成127.0.0.1 把socket.AI_PASSIVE去掉。
有的时候,你通过getaddrinfo去获得的地址很多你都用不了,比如你的机器只支持IPv4而目标机器支持IPv4和IPv6。通过下面的方式你就可以获得你可以使用的地址
>>> getaddrinfo('ftp.kernel.org', 'ftp', 0, socket.SOCK_STREAM, 0, ... socket.AI_ADDRCONFIG | socket.AI_V4MAPPED) [(2, 1, 6, '', ('204.152.191.37', 21)), (2, 1, 6, '', ('149.20.20.133', 21))]
socket.AI_ADDRCONFIG这个参数让getaddrinfo返回你可以使用的地址。
那么这里使用的socket.AI_V4MAPPED是做什么用的呢? 考虑下面这种情况。你的机器仅支持IPv6而你要访问的服务仅支持IPv4。用了这个参数,返回的地址会做一些处理,映射成ipv6格式 这样你就可以连接该服务了。
回顾之前说的getaddrinfo返回的地址格式是ftpca。 这里的c是conninonical name。 但是可以看到之前返回的这个位置都是空的。那么怎么样才能获得这个值呢?用下面的方式。
>>> getaddrinfo('iana.org', 'www', 0, socket.SOCK_STREAM, 0, ... socket.AI_ADDRCONFIG | socket.AI_V4MAPPED | socket.AI_CANONNAME) [(2, 1, 6, '43-8.any.icann.org', ('192.0.43.8', 80))]