Python底层socket库

时间:2021-02-13 08:49:37

Python底层socket库将Unix关于网络通信的系统调用对象化处理,是底层函数的高级封装,socket()函数返回一个套接字,它的方法实现了各种套接字系统调用。read与write与Python对文件的操作一致,缓冲区都是自动分配的。

套接字地址有多种表示方式,分为不同的系列。

AF_UNIX地址系列:单个字符串

AF_INET地址系列:(host,port),其中host可以为主机名也可以为ip地址,port为整数。如(“www.host.com”,10)或(“100.200.50.0”,10)

AF_INET6地址系列:(host, port, flowinfo, scopeid),其中flowinfo和scopeid表示在C中的struct sockaddr_in6中的sin6_flowinfo和sin6_scope_id成员。对于套接字模块方法,flowinfo和scopeid可以省略以向前兼容。

对于IPv4地址,接受两种特殊形式而不是主机地址:空字符串表示INADDR_ANY,字符串'<broadcast>'表示INADDR_BROADCAST。 此行为不可用于IPv6以实现向后兼容性,因此,如果您打算使用Python程序支持IPv6,则可能需要避免这些行为。

如果在IPv4 / v6套接字地址的主机部分使用主机名,程序可能会显示非确定性行为,因为Python使用从DNS解析返回的第一个地址。 根据DNS解析和/或主机配置的结果,套接字地址将以不同的方式解析为实际的IPv4 / v6地址。 对于确定性行为,在主机部分中使用数字地址。

所有错误引发异常。 可以提出无效参数类型和内存不足条件的正常异常; 与套接字或地址语义相关的错误会引发错误socket.error。

通过setblocking()支持非阻塞模式。 通过settimeout()支持基于超时的泛化。

模块套接字导出以下常量和函数:

异常socket.error
对于与套接字相关的错误,引发此异常。 附带的值是一个字符串,它告诉出错了什么,或者一个对(errno,string)表示系统调用返回的错误,类似于os.error的值。 请参见模块errno,其中包含由底层操作系统定义的错误代码的名称。

在版本2.6中更改:socket.error现在是一个IOError类的子类。

异常socket.herror
对于与地址相关的错误,即对于在C API中使用h_errno的函数(包括gethostbyname_ex()和gethostbyaddr()),引发此异常。

附带的值是一个表(h_errno,string),表示库调用返回的错误。 string表示由hstrerror()C函数返回的h_errno的描述。

异常socket.gaierror
对于getaddrinfo()和getnameinfo(),与地址相关的错误引发了此异常。 附带的值是一个对(错误,字符串),表示库调用返回的错误。 string表示由gai_strerror()C函数返回的错误的描述。 错误值将匹配此模块中定义的一个EAI_ *常量。

异常socket.timeout
当在通过先前调用settimeout()启用了超时的套接字上发生超时时,会引发此异常。 附带的值是一个字符串,其值目前总是“超时”。

socket.AF_UNIX
socket.AF_INET
socket.AF_INET6
这些常量表示地址(和协议)族,用于socket()的第一个参数。 如果未定义AF_UNIX常数(指定协议),则不支持此协议。

socket.SOCK_STREAM
socket.SOCK_DGRAM
socket.SOCK_RAW
socket.SOCK_RDM
socket.SOCK_SEQPACKET
这些常量表示套接字类型,用于socket()的第二个参数。 (只有SOCK_STREAM和SOCK_DGRAM似乎通常有用。)

SO_*
socket.SOMAXCONN
MSG_ *
SOL_ *
IPPROTO_ *
IPPORT_ *
INADDR_ *
IP_ *
IPV6_ *
EAI_ *
AI_ *
NI_ *
TCP_ *
在套接字模块中定义了在Unix文档中有关套接字和/或IP协议的常量。 它们通常用于套接字对象的setsockopt()和getsockopt()方法的参数。 在大多数情况下,只定义在Unix头文件中定义的那些符号; 对于几个符号,提供默认值。

SIO_ *
RCVALL_ *
Windows的WSAIoctl()的常量。 常量用作套接字对象的ioctl()方法的参数。

socket.has_ipv6
此常量包含一个布尔值,指示此平台是否支持IPv6。

socket.create_connection(address [,timeout [,source_address]])
连接到侦听Internet地址(2元组(主机,端口))的TCP服务,并返回套接字对象。 这是比socket.connect()更高级的函数:如果主机是非数字主机名,它将尝试为AF_INET和AF_INET6解析它,然后尝试连接到所有可能的地址,直到连接成功 。 这使得编写与IPv4和IPv6兼容的客户端变得容易。

传递可选的timeout参数将在尝试连接之前设置套接字实例上的超时。 如果未提供超时,将使用getdefaulttimeout()返回的全局默认超时设置。

如果提供,source_address必须是连接之前套接字绑定为其源地址的2元组(主机,端口)。 如果主机或端口分别为''或0,将使用操作系统默认行为。

在版本2.7中更改:添加了source_address。

socket.getaddrinfo(host,port [,family [,socktype [,proto [,flags]]]])
将host / port参数转换为5元组序列,其中包含创建连接到该服务的套接字所需的所有参数。 host是域名,IPv4 / v6地址的字符串表示形式或None。 port是一个字符串服务名称,如“http”,数字端口号或无。通过传递None作为主机和端口的值,您可以传递NULL到底层的C API。

可以可选地指定family,socktype和proto参数,以缩小返回的地址列表。默认情况下,它们的值为0,表示选择了完整范围的结果。 flags参数可以是一个或多个AI_ *常量,并且将影响如何计算和返回结果。其默认值为0.例如,AI_NUMERICHOST将禁用域名解析,并且如果主机是域名,则会引发错误。

该函数返回具有以下结构的5元组列表:

(family,socktype,proto,canonname,sockaddr)

在这些元组中,family,socktype,proto都是整数,并且被传递给socket()函数。 canonname将是一个字符串,表示主机的规范名称,如果AI_CANONNAME是flags参数的一部分;否则canonname将为空。 sockaddr是描述套接字地址的元组,其格式取决于返回的族(AF_INET的a(地址,端口)2元组,AF_INET6的(地址,端口,流信息,作用域id)4元组)意味着要传递给socket.connect()方法。

以下示例获取在端口80上与example.org的假设TCP连接的地址信息(如果未启用IPv6,则系统上的结果可能会有所不同):

>>> socket.getaddrinfo("example.org", 80, 0, 0, socket.IPPROTO_TCP)
[(10, 1, 6, '', ('2606:2800:220:1:248:1893:25c8:1946', 80, 0, 0)),
(2, 1, 6, '', ('93.184.216.34', 80))]

socket.getfqdn([name])
返回名称的完全限定域名。 如果name被省略或为空,它将被解释为本地主机。 要查找完全限定名,将检查由gethostbyaddr()返回的主机名,然后是主机的别名(如果可用)。 选择包含句点的名字。 如果没有完全限定的域名可用,则返回由gethostname()返回的主机名。

socket.gethostbyname(hostname)将主机名转换为IPv4地址格式。 IPv4地址作为字符串返回,例如'100.50.200.5'。 如果主机名是IPv4地址本身,则返回不变。 请参阅gethostbyname_ex()以获取更完整的接口。 gethostbyname()不支持IPv6名称解析,而getaddrinfo()应该用于IPv4 / v6双栈支持。

socket.gethostbyname_ex(hostname)
将主机名转换为IPv4地址格式,扩展接口。 返回一个三元组(hostname,aliaslist,ipaddrlist),其中hostname是响应给定ip_address的主主机名,aliaslist是同一地址的备用主机名列表(可能为空),ipaddrlist是同一主机上的同一接口(通常但不总是单个地址)的IPv4地址列表 。 gethostbyname_ex()不支持IPv6名称解析,而应使用getaddrinfo()替代IPv4 / v6双栈支持。

socket.gethostname()
返回一个字符串,其中包含Python解释器当前正在执行的机器的主机名。

如果你想知道当前机器的IP地址,你可能想使用gethostbyname(gethostname())。 此操作假定对于主机存在有效的地址到主机映射,并且假设并不总是成立。

注意:gethostname()不总是返回完全限定的域名; 使用getfqdn()(见上文)。

socket.gethostbyaddr(ip_address)
返回一个三元组(hostname,aliaslist,ipaddrlist)其中hostname是响应给定ip_address的主主机名,aliaslist是同一地址的一个(可能为空的)备用主机名列表,ipaddrlist是IPv4 / v6地址列表 对于同一主机上的同一接口(很可能只包含单个地址)。 要查找完全限定的域名,请使用函数getfqdn()。 gethostbyaddr()支持IPv4和IPv6。

socket.getnameinfo(sockaddr,flags)
将套接字地址sockaddr转换成2元组(主机,端口)。 根据标志的设置,结果可以在主机中包含完全限定的域名或数字地址表示。 类似地,port可以包含字符串端口名或数字端口号。

socket.getprotobyname(protocolname)
将Internet协议名称(例如,'icmp')转换为适合作为socket()函数的(可选)第三个参数传递的常量。 这通常仅在以“原始”模式(SOCK_RAW)打开的插座需要; 对于正常的套接字模式,如果协议被省略或零,则自动选择正确的协议。

socket.getservbyname(servicename [,protocolname])
将Internet服务名称和协议名称转换为该服务的端口号。 可选的协议名称,如果给出,应该是'tcp'或'udp',否则任何协议将匹配。

socket.getservbyport(port [,protocolname])
将Internet端口号和协议名称转换为该服务的服务名称。 可选的协议名称,如果给出,应该是'tcp'或'udp',否则任何协议将匹配。

socket.socket([family [,type [,proto]]])
使用给定的地址族,套接字类型和协议号创建一个新的套接字。 地址系列应为AF_INET(默认值),AF_INET6或AF_UNIX。 套接字类型应该是SOCK_STREAM(默认值),SOCK_DGRAM或者其他SOCK_常量之一。 协议号通常为零,在这种情况下可以省略。

socket.socketpair([family [,type [,proto]]])
使用给定的地址族,套接字类型和协议号构建一对连接的套接字对象。 地址族,套接字类型和协议号与上面的socket()函数一样。 如果在平台上定义,默认系列是AF_UNIX; 否则,默认值为AF_INET。 支持平台:Unix。

socket.fromfd(fd,family,type [,proto])
复制文件描述符fd(由文件对象的fileno()方法返回的整数),并从结果中构建一个套接字对象。 地址族,套接字类型和协议号与上面的socket()函数一样。 文件描述符应该引用套接字,但这不是选中的 - 如果文件描述符无效,对象上的后续操作可能会失败。 此函数很少需要,但可用于获取或设置作为标准输入或输出传递给程序的套接字选项(例如由Unix inet守护程序启动的服务器)。 假定套接字处于阻塞模式。 支持平台:Unix。

socket.ntohl(x)
将32位正整数从网络转换为主机字节顺序。 在主机字节顺序与网络字节顺序相同的机器上,这是一个无操作; 否则,它执行4字节交换操作。

socket.ntohs(x)
将16位正整数从网络转换为主机字节顺序。 在主机字节顺序与网络字节顺序相同的机器上,这是一个无操作; 否则,它执行2字节交换操作。

socket.htons(x)
将16位正整数从主机转换为网络字节顺序。 在主机字节顺序与网络字节顺序相同的机器上,这是一个无操作; 否则,它执行2字节交换操作。

socket.inet_aton(ip_string)
将IPv4地址从点分四元字符串格式(例如,“123.45.67.89”)转换为32位打包二进制格式,长度为四个字符的字符串。 这在与使用标准C库的程序交谈时需要类型struct in_addr的对象,这是该函数返回的32位打包二进制的C类型。

inet_aton()也接受少于三个点的字符串; 有关详细信息,请参阅Unix手册页inet(3)。

如果传递给此函数的IPv4地址字符串无效,则会抛出套接字错误。 注意,什么是有效的取决于inet_aton()的底层C实现。

inet_aton()不支持IPv6,而应使用inet_pton()代替IPv4 / v6双栈支持。

socket.inet_ntoa(packed_ip)
将32位压缩IPv4地址(长度为四个字符的字符串)转换为其标准点分四元字符串表示形式(例如,“123.45.67.89”)。 这在与使用标准C库的程序交谈时需要类型struct in_addr的对象,这是该函数作为参数的32位打包二进制数据的C类型。

如果传递给这个函数的字符串的长度不是4个字节,则会抛出socket.error。 inet_ntoa()不支持IPv6,而应使用inet_ntop()代替IPv4 / v6双栈支持。

socket.inet_pton(address_family,ip_string)
将IP地址从其特定于家庭的字符串格式转换为压缩的二进制格式。 当库或网络协议调用类型为struct in_addr的对象(类似于inet_aton())或struct in6_addr时,inet_pton()非常有用。

address_family的支持值当前为AF_INET和AF_INET6。 如果IP地址字符串ip_string无效,socket.error将被引发。 请注意,什么是有效的取决于address_family的值和inet_pton()的底层实现。

可用性:Unix(也许不是所有的平台)。

socket.inet_ntop(address_family,packed_ip)
将一个打包的IP地址(一些字符串的字符串)转换为其标准的特定于家庭的字符串表示形式(例如,'7.10.0.5'或'5aef:2b :: 8')inet_ntop 或网络协议返回类型为struct in_addr(类似于inet_ntoa())或struct in6_addr的对象。

address_family的支持值当前为AF_INET和AF_INET6。 如果字符串packed_ip不是指定地址系列的正确长度,则会引发ValueError。 在调用inet_ntop()时产生错误的socket.error。

可用性:Unix(也许不是所有的平台)。

socket.getdefaulttimeout()
返回新套接字对象的默认超时值(以秒为单位)(float)。 值为None表示新的套接字对象没有超时。 首次导入套接字模块时,默认值为None。

socket.setdefaulttimeout(timeout)
为新的套接字对象设置默认超时(以秒为单位)(float)。 值为None表示新的套接字对象没有超时。 首次导入套接字模块时,默认值为None。

socket.SocketType
这是一个表示套接字对象类型的Python类型对象。 它与类型(socket(...))相同。

Socket Objects

Socket对象有以下方法。 除了makefile(),这些对应于适用于套接字的Unix系统调用。

socket.accept()
接受连接。 套接字必须绑定到地址并侦听连接。 返回值是一对(conn,address),其中conn是可用于在连接上发送和接收数据的新套接字对象,而address是绑定到连接另一端的套接字的地址。

socket.bind(地址)
将套接字绑定到地址。 套接字不必已绑定。 (地址格式取决于地址系列 - 请参见上文。)

注意此方法历史上接受了一对AF_INET地址的参数,而不只是一个元组。 这从未是有意的,在Python 2.0和更高版本中不再可用。
socket.close()
关闭套接字。 对套接字对象的所有未来操作都将失败。 远程端将不再接收数据(在排队的数据被刷新之后)。 套接字在被垃圾回收时自动关闭。

注意close()释放与连接相关联的资源,但不一定立即关闭连接。 如果要及时关闭连接,请在close()之前调用shutdown()。

socket.connect(address)
在地址处连接到远程套接字。 (地址格式取决于地址系列 - 请参见上文。)

注意此方法历史上接受了一对AF_INET地址的参数,而不只是一个元组。 这从未是有意的,在Python 2.0和更高版本中不再可用。

socket.connect_ex(address)
像连接(地址),但返回一个错误指示器,而不是引起C级别connect()调用返回的错误的异常(其他问题,如“主机未找到”,仍然可能引发异常)。 如果操作成功,错误指示符为0,否则为errno变量的值。 这对于支持例如异步连接是有用的。

注意此方法历史上接受了一对AF_INET地址的参数,而不只是一个元组。 这从未是有意的,在Python 2.0和更高版本中不再可用。

socket.fileno()
返回套接字的文件描述符(一个小整数)。 这对select.select()很有用。

在Windows下,此方法返回的小整数不能用于可以使用文件描述符的位置(例如os.fdopen())。 Unix没有这个限制。

socket.getpeername()
返回套接字连接的远程地址。 这有助于找出例如远程IPv4 / v6套接字的端口号。 (返回的地址格式取决于地址族 - 见上文)。在某些系统上,不支持此功能。

socket.getsockname()
返回套接字自己的地址。 例如,这有助于找出IPv4 / v6套接字的端口号。 (返回的地址格式取决于地址族 - 见上文。)

socket.getsockopt(level,optname [,buflen])
返回给定套接字选项的值(参见Unix手册页getsockopt(2))。 所需的符号常量(SO_ *等)在此模块中定义。 如果buflen不存在,则假定为整数选项,并且其整数值由函数返回。 如果buflen存在,它指定用于接收选项的缓冲区的最大长度,并且此缓冲区作为字符串返回。 它由调用者解码缓冲区的内容(参见可选的内置模块结构体,用于解码编码为字符串的C结构)。

 
socket.ioctl(控制,选项)
平台:Windows
ioctl()方法是WSAIoctl系统接口的有限接口。 有关详细信息,请参阅Win32文档。

在其他平台上,可以使用通用的fcntl.fcntl()和fcntl.ioctl()函数; 他们接受一个套接字对象作为它们的第一个参数。

socket.listen(backlog)
监听与套接字的连接。 backlog参数指定排队的连接的最大数量,并且应至少为0; 最大值是系统相关的(通常为5),最小值被强制为0。

socket.makefile([mode [,bufsize]])
返回与套接字相关联的文件对象。 (文件对象在文件对象中描述。)当调用close()方法时,文件对象不会明确地关闭套接字,而只是删除它对套接字对象的引用,因此套接字将被关闭 从任何地方。

套接字必须处于阻塞模式(它不能有超时)。 可选模式和bufsize参数的解释方式与内置file()函数相同。

注意在Windows上,由makefile()创建的类文件对象不能用于具有文件描述符的文件对象,例如subprocess.Popen()的流参数。

socket.recv(bufsize [,flags])
从套接字接收数据。 返回值是表示接收到的数据的字符串。 一次性接收的最大数据量由bufsize指定。请参阅可选参数标志的含义Unix手册中的recv(2); 它默认为零。

注意为了与硬件和网络实际情况最佳匹配,bufsize的值应为2的相对较小的幂,例如4096。

socket.recvfrom(bufsize [,flags])
从套接字接收数据。 返回值是一对(字符串,地址),其中string是表示接收到的数据的字符串,address是发送数据的套接字的地址。请参阅可选参数标志的含义Unix手册中的recv(2); 它默认为零。 (地址格式取决于地址系列 - 请参见上文。)

socket.recvfrom_into(buffer [,nbytes [,flags]])
从套接字接收数据,将其写入缓冲区,而不是创建一个新的字符串。 返回值是一对(nbytes,地址),其中nbytes是接收的字节数,address是发送数据的套接字的地址。请参阅可选参数标志的含义Unix手册中的recv(2); 它默认为零。 (地址格式取决于地址系列 - 请参见上文。)

socket.recv_into(buffer [,nbytes [,flags]])
从套接字接收最多nbytes字节,将数据存储到缓冲区中,而不是创建一个新的字符串。 如果未指定nbytes(或0),请接收达到给定缓冲区中可用的大小。 返回接收的字节数。请参阅可选参数标志的含义Unix手册中的recv(2); 它默认为零。

socket.send(string [,flags])
将数据发送到套接字。 插座必须连接到远程插座。 可选的flags参数与上面的recv()有相同的含义。 返回发送的字节数。 应用程序负责检查所有数据是否已发送; 如果仅传输了一些数据,则应用程序需要尝试传递剩余的数据。 有关此概念的更多信息,请参阅套接字编程HOWTO。

socket.sendall(string [,flags])
将数据发送到套接字。 插座必须连接到远程插座。 可选的flags参数与上面的recv()有相同的含义。 与send()不同,此方法继续从字符串发送数据,直到发送所有数据或发生错误。 成功返回无。 出现错误时,会引发异常,并且无法确定已成功发送多少数据(如果有)。

socket.sendto(string,address)
socket.sendto(string,flags,address)
将数据发送到套接字。 套接字不应连接到远程套接字,因为目标套接字由地址指定。 可选的flags参数与上面的recv()有相同的含义。 返回已发送的字节数。 (地址格式取决于地址系列 - 请参见上文。)

socket.setblocking(flag)
设置套接字的阻塞或非阻塞模式:如果标志为0,套接字设置为非阻塞,否则设置为阻塞模式。 最初,所有套接字都处于阻塞模式。 在非阻塞模式下,如果recv()调用没有找到任何数据,或者send()调用不能立即处理数据,则会引发错误异常; 在阻塞模式下,调用阻塞,直到它们可以继续。 s.setblocking(0)等价于s.settimeout(0.0); s.setblocking(1)等效于s.settimeout(None)。

socket.settimeout(value)
设置阻塞套接字操作的超时。 value参数可以是表示秒的非负浮点数,或None。 如果给出了一个浮点数,如果超时周期值在操作完成之前已过,则后续套接字操作将引发一个超时异常。 设置超时为None将禁用套接字操作的超时。 s.settimeout(0.0)相当于s.setblocking(0); s.settimeout(None)等价于s.setblocking(1)。

socket.gettimeout()
返回与套接字操作相关联的超时(以秒为单位)(float),如果未设置超时,则返回None。 这反映了对setblocking()或settimeout()的最后调用。

关于套接字阻塞和超时的一些注意事项:套接字对象可以是以下三种模式之一:阻塞,非阻塞或超时。套接字始终在阻塞模式下创建。在阻塞模式下,操作阻塞直到完成或系统返回错误(例如连接超时)。在非阻塞模式下,如果无法立即完成操作,操作将失败(具有不幸的系统依赖的错误)。在超时模式下,如果无法在为套接字指定的超时内完成操作或系统返回错误,则操作将失败。 setblocking()方法只是某些settimeout()调用的简写。

超时模式在内部将套接字设置为非阻塞模式。阻塞和超时模式在引用同一网络端点的文件描述符和套接字对象之间共享。这样做的后果是,只有当套接字处于阻塞模式时,才使用由makefile()方法返回的文件对象;在超时或非阻塞模式下,无法立即完成的文件操作将失败。

注意,connect()操作受超时设置的限制,通常建议在调用connect()之前调用settimeout()或者将超时参数传递给create_connection()。无论任何Python套接字超时设置,系统网络堆栈都可能返回其自身的连接超时错误。

socket.setsockopt(level,optname,value)
设置给定套接字选项的值(请参见Unix手册页setsockopt(2))。 所需的符号常量在套接字模块(SO_ *等)中定义。 该值可以是表示缓冲区的整数或字符串。 在后一种情况下,由调用者确保字符串包含适当的位(参见可选的内置模块结构体,用于将C结构编码为字符串)。

socket.shutdown(how)
关闭连接的一半或两半。 如果how为SHUT_RD,则不允许进一步接收。 如果how为SHUT_WR,则不允许进一步发送。 如果SHUT_RDWR如何,则不允许进一步发送和接收。 根据平台,关闭一半的连接也可以关闭对面的一半(例如,在Mac OS X上,关闭(SHUT_WR)不允许在连接的另一端进一步读取)。

注意没有方法read()或write(); 使用recv()和send()而不使用flags参数。

Socket对象也有这些(只读)属性,对应于给套接字构造函数的值。

socket.family
插座系列。

socket.type
套接字类型。

socket.proto
套接字协议。