getaddrinfo学习

使用socket时,会使用socket.socket(socket.AF_INET,socket.SOCK.DGRAM)来建立一个socket。而后用其来绑定(bind((IP,Port)))或者链接,那么,参数AF_INET和DGRAM是什么意思呢,是否还有其它的参数呢?python

这里能够看到,咱们使用了4个参数:socket.AF_INET,socket.SOCK.DGRAM,IP,Port;可是在建立socket的时候有三个参数,只不过默认参数被忽略了。服务器

首先,地址族是最重要的参数,机器可能接触不一样类型的网络,对地址族的指定就决定了想要进行通讯的网络类型。在学习的时候,一直使用的是socket.AF_INET即IP地址族。按照tcp/ip层分类,这个参数指的是IP层的协议,固然,不止有ip协议,还有蓝牙协议,wifi协议等等网络

第二个就是套接字类型,这里使用的是socket.SOCK.DGRAM,固然,在IP协议之上有tcp何udp之分,那么在其余ip层协议之上,咱们该怎么办呢?这里设计者使用的是普遍可使用的接口参数,例如:这里使用的socket.SOCK.DGRAM表明使用套接字数据报文传输,在IP协议上就是指UDP,而socket.STREAM指的是可靠的传输,在IP上指的是TCP。那么在其余协议之上的传输也可使用。socket

第三个参数是协议类型,好比上面例子中socket.socket(socket.AF_INET,socket.SOCK.DGRAM)就是指在ip协议中选择基于数据报的传输模式协议,那么在ip协议中就是指的是UDP,不须要再输入协议类型了,若是真要输入协议类型,UDP是17,TCP是6,固然通常默认是0,就是让下层程序自动挑选,反正通过前面两个参数能够指定了,后面这个通常默认便可。tcp

绑定(bind((IP,Port)))或者链接的时候呢,就是ip地址和端口,没啥多说的。ide

那么在实际使用中,咱们使用getaddrinfo来获取相关的信息。函数

getaddrinfo函数的参数:socket.getaddrinfo(host, port[, family[, socktype[, proto[, flags]]]])学习

首先,host是想要获取的ip地址或者能够经过hosts or DNS解析的字符串,port就是端口(int)或者能够经过/etc/services解析的字符串,第三个是网络层的协议类型,第四个就是传输层的协议类型,第五个就是经过第三个参数和第四个参数肯定的协议中的哪个,通常来讲只有一个,因此通常默认为0便可,最后一个就是一些设置参数。设计

返回值[(family, socktype, proto, canonname, sockaddr)]3d

首先就是网络层协议,而后是传输层协议,而后是协议编号,canonname不清楚了,sockaddr就是一个元组例如:('220.181.38.148', 80);包含了ip和端口。

clipboard

当使用getaddrinfo获取信息的时候,最后一个参数很是有用,

首先,若是指定ip地址为None,那么其意义就是获取本地信息,最后一个参数使用socket.AI_PASSIVE就能够获取本地全部能够链接的指定端口的信息,

clipboard

若是指定了一个ip,那么久应该取消socket.AI_PASSIVE这个参数,设置为0或者其余参数便可。

还有一个是AI_ADDRCONFIG,这个参数能够把IP地址上没法链接的地址都过滤掉。例如,若是本机只能使用ipv4来链接,而对方能够接收ipv4和ipv6,那么这个参数会将ipv6的地址都去掉。

AI_V4MAPPED能够将ipv4的地址转换成ipv6的地址,例如,咱们想链接的服务只支持ipv4,可是本机只能使用ipv6,那么使用这个参数能够将v4转化为v6。

参数使用举例:

当我想链接百度的HTTP端口:

from pprint import pprint import socket if __name__== '__main__': infolist = socket.getaddrinfo('baidu.com','www',0,socket.SOCK_STREAM,0,socket.AI_ADDRCONFIG | socket.AI_V4MAPPED) pprint((infolist))

[(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 0, '', ('39.156.69.79', 80)), (<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 0, '', ('220.181.38.148', 80))]

当咱们知道ip和端口后,可是咱们不知道这个主机的DNS真实名称,好比,我被告知192.168.10.22时百度的地址,端口是80,而后我也这样访问了,能够链接上,可是这个ip地址是内网地址,是总所周知的,可是,服务器方能够另DNS返回任意他们想要返回的结果,这里他们就可让DNS返回百度的真实名称给客户端,致使客户端认为这就是百度。

使用这个方式的办法是使用AI_CANONNAME参数,以下:

clipboard

这种使用只有在服务器定义了反向主机名的时候才有用,可是在互联网上,不多有服务器提供了反向主机名,因此须要用其它方式来确认。

其它参数:

clipboard

使用例子:

import socket,sys,argparse def connect_to(hostname_or_ip): try: infolist = socket.getaddrinfo(hostname_or_ip,'www',0,socket.SOCK_STREAM,0,socket.AI_ADDRCONFIG | socket.AI_V4MAPPED | socket.AI_CANONNAME) except socket.gaierror as why: print('Name Service failure:',why.args[1]) sys.exit(1) info = infolist[0] socket_args = info[0:3] address = info[4] s = socket.socket(*socket_args) try: s.connect(address) except socket.error as why: print('Network failure:',why.args[1]) else: print(F'Success:host {address[0]} is listening on port 80.') if __name__ == '__main__': parse = argparse.ArgumentParser(description='Try connect to port 80') parse.add_argument('hostname',help='hostname you want to connect') connect_to(parse.parse_args().hostname)

python tcp_sixteen.py baidu.com Success:host 220.181.38.148 is listening on port 80. python tcp_sixteen.py 220.181.38.148 Success:host 220.181.38.148 is listening on port 80.

相关文章
相关标签/搜索