17.2. socket — 低级网络接口 — Python 文档

来自菜鸟教程
Python/docs/2.7/library/socket
跳转至:导航、​搜索

17.2. 插座 — 低级网络接口

该模块提供对 BSD socket 接口的访问。 它适用于所有现代 Unix 系统、Windows、Mac OS X、BeOS、OS/2 以及可能的其他平台。

笔记

某些行为可能取决于平台,因为调用的是操作系统套接字 API。


有关套接字编程(C 语言)的介绍,请参阅以下论文:Stuart Sechrest 的介绍性 4.3BSD 进程间通信教程和 Samuel J 的高级 4.3BSD 进程间通信教程。 Leffler 等人,均在 UNIX Programmer's Manual, Supplementary Documents 1(PS1:7 和 PS1:8 部分)中。 各种与套接字相关的系统调用的特定于平台的参考资料也是有关套接字语义细节的宝贵信息来源。 对于 Unix,请参阅手册页; 对于 Windows,请参阅 WinSock(或 Winsock 2)规范。 对于支持 IPv6 的 API,读者可能需要参考 RFC 3493 标题为 IPv6 的基本套接字接口扩展。

Python 接口是 Unix 系统调用和套接字库接口到 Python 面向对象风格的直接音译:socket() 函数返回一个 socket 对象 ,它的方法实现了各种套接字系统调用。 参数类型比 C 接口中的级别更高:与 Python 文件上的 read()write() 操作一样,接收操作的缓冲区分配是自动的,并且缓冲区长度在发送操作中是隐式的。

套接字地址表示如下: AF_UNIX 地址族使用单个字符串。 一对 (host, port) 用于 AF_INET 地址族,其中 host 是一个字符串,表示互联网域符号中的主机名,如 'daring.cwi.nl' 或IPv4 地址如 '100.50.200.5'port 是一个整数。 对于 AF_INET6 地址族,使用四元组 (host, port, flowinfo, scopeid),其中 flowinfoscopeid 代表 sin6_flowinfosin6_scope_id 成员在 C 中的 struct sockaddr_in6。 对于 socket 模块方法,为了向后兼容,可以省略 flowinfoscopeid。 但是请注意,省略 scopeid 可能会导致操作范围内的 IPv6 地址出现问题。 目前不支持其他地址族。 根据创建套接字对象时指定的地址族自动选择特定套接字对象所需的地址格式。

对于 IPv4 地址,接受两种特殊形式而不是主机地址:空字符串表示 INADDR_ANY,字符串 '<broadcast>' 表示 INADDR_BROADCAST。 为了向后兼容,该行为不适用于 IPv6,因此,如果您打算在 Python 程序中支持 IPv6,您可能希望避免这些。

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

2.5 版新功能:AF_NETLINK 套接字表示为对 pid, groups


2.6 版新功能:Linux 仅支持 TIPC 也可使用 AF_TIPC 地址系列。 TIPC 是一种开放的、基于非 IP 的网络协议,设计用于集群计算机环境。 地址由元组表示,字段取决于地址类型。 一般元组形式为 (addr_type, v1, v2, v3 [, scope]),其中:

  • addr_typeTIPC_ADDR_NAMESEQTIPC_ADDR_NAMETIPC_ADDR_ID 之一。

  • scopeTIPC_ZONE_SCOPETIPC_CLUSTER_SCOPETIPC_NODE_SCOPE 之一。

  • 如果 addr_typeTIPC_ADDR_NAME,那么 v1 是服务器类型,v2 是端口标识符,而 v3 应该为 0。

    如果 addr_typeTIPC_ADDR_NAMESEQ,则 v1 是服务器类型,v2 是较低的端口号,而 v3是上面的端口号。

    如果addr_typeTIPC_ADDR_ID,则v1为节点,v2为参考,并设置v3到 0。


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

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

模块 socket 导出以下常量和函数:

exception socket.error

与套接字相关的错误会引发此异常。 伴随的值要么是一个字符串,说明出了什么问题,要么是一对 (errno, string) 表示系统调用返回的错误,类似于伴随 os.error 的值。 请参阅模块 errno,其中包含由底层操作系统定义的错误代码的名称。

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

exception socket.herror

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

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

exception socket.gaierror
此异常是针对地址相关错误引发的,例如 getaddrinfo()getnameinfo()。 伴随的值是一对 (error, string) 表示库调用返回的错误。 string 表示 error 的描述,由 gai_strerror() C 函数返回。 error 值将匹配此模块中定义的 EAI_* 常量之一。
exception socket.timeout

当通过先前调用 settimeout() 启用超时的套接字上发生超时时,会引发此异常。 伴随的值是一个字符串,其值当前总是“超时”。

2.3 版中的新功能。

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_STREAMSOCK_DGRAM 似乎普遍有用。)
SO_*

socket.SOMAXCONN
MSG_*
SOL_*
IPPROTO_*
IPPORT_*
INADDR_*
IP_*
IPV6_*
EAI_*
AI_*
NI_*
TCP_*

这些形式的许多常量,记录在关于套接字和/或 IP 协议的 Unix 文档中,也在套接字模块中定义。 它们通常用于套接字对象的 setsockopt()getsockopt() 方法的参数中。 大多数情况下,只定义那些在 Unix 头文件中定义的符号; 对于一些符号,提供了默认值。
SIO_*
RCVALL_*

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

2.6 版中的新功能。

TIPC_*

TIPC 相关常量,匹配 C 套接字 API 导出的常量。 有关详细信息,请参阅 TIPC 文档。

2.6 版中的新功能。

socket.has_ipv6

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

2.3 版中的新功能。

socket.create_connection(address[, timeout[, source_address]])

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

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

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

2.6 版中的新功能。

2.7 版更改:添加了 source_address

socket.getaddrinfo(host, port[, family[, socktype[, proto[, flags]]]])

host/port 参数转换为 5 元组序列,其中包含创建连接到该服务的套接字所需的所有参数。 host 是一个域名,一个 IPv4/v6 地址的字符串表示或 Noneport 是字符串服务名称,例如 'http'、数字端口号或 None。 通过将 None 作为 hostport 的值传递,您可以将 NULL 传递给底层 C API。

可以选择指定 familysocktypeproto 参数以缩小返回的地址列表。 默认情况下,它们的值为 0,这意味着选择了完整范围的结果。 flags 参数可以是 AI_* 常量中的一个或几个,并将影响结果的计算和返回方式。 其默认值为 0。 例如,AI_NUMERICHOST 将禁用域名解析,如果 host 是域名,则会引发错误。

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

(family, socktype, proto, canonname, sockaddr)

在这些元组中,familysocktypeproto 都是整数,并打算传递给 socket() 函数。 canonname 将是一个字符串,表示 host 的规范名称,如果 AI_CANONNAMEflags 参数的一部分; 否则 canonname 将为空。 sockaddr 是一个描述套接字地址的元组,其格式取决于返回的 family(一个 (address, port) 2-tuple for AF_INET,一个 [ X162X] 用于 AF_INET6) 的 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))]

2.2 版中的新功能。

socket.getfqdn([name])

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

2.0 版中的新功能。

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 元组 (host, port)。 根据 flags 的设置,结果可以包含完全限定的域名或 host 中的数字地址表示。 同样,port 可以包含字符串端口名称或数字端口号。

2.2 版中的新功能。

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_INET6AF_UNIX。 套接字类型应为 SOCK_STREAM(默认值)、SOCK_DGRAM 或其他 SOCK_ 常量之一。 协议编号通常为零,在这种情况下可以省略。
socket.socketpair([family[, type[, proto]]])

使用给定的地址族、套接字类型和协议号构建一对连接的套接字对象。 地址族、套接字类型和协议编号与上面的 socket() 函数相同。 如果在平台上定义,则默认系列为 AF_UNIX; 否则,默认值为 AF_INET。 可用性:Unix。

2.4 版中的新功能。

socket.fromfd(fd, family, type[, proto])
复制文件描述符 fd(文件对象的 fileno() 方法返回的整数)并根据结果构建套接字对象。 地址族、套接字类型和协议编号与上面的 socket() 函数相同。 文件描述符应该引用一个套接字,但这不会被检查——如果文件描述符无效,对对象的后续操作可能会失败。 此函数很少需要,但可用于获取或设置作为标准输入或输出传递给程序的套接字上的套接字选项(例如由 Unix inet 守护程序启动的服务器)。 假定套接字处于阻塞模式。 可用性:Unix。
socket.ntohl(x)
将 32 位正整数从网络转换为主机字节顺序。 在主机字节顺序与网络字节顺序相同的机器上,这是一个空操作; 否则,它执行 4 字节交换操作。
socket.ntohs(x)
将 16 位正整数从网络转换为主机字节顺序。 在主机字节顺序与网络字节顺序相同的机器上,这是一个空操作; 否则,它执行 2 字节交换操作。
socket.htonl(x)
将 32 位正整数从主机转换为网络字节顺序。 在主机字节顺序与网络字节顺序相同的机器上,这是一个空操作; 否则,它执行 4 字节交换操作。
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 地址字符串无效,则会引发 socket.error。 请注意,究竟什么有效取决于 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.errorinet_ntoa() 不支持 IPv6,应使用 inet_ntop() 代替 IPv4/v6 双栈支持。

socket.inet_pton(address_family, ip_string)

将 IP 地址从特定于系列的字符串格式转换为打包的二进制格式。 inet_pton() 在库或网络协议调用类型为 struct in_addr(类似于 inet_aton())或 struct in6_addr 的对象时很有用。

address_family 目前支持的值为 AF_INETAF_INET6。 如果 IP 地址字符串 ip_string 无效,则会引发 socket.error。 请注意,究竟什么有效取决于 address_family 的值和 inet_pton() 的底层实现。

可用性:Unix(可能不是所有平台)。

2.3 版中的新功能。

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_INETAF_INET6。 如果字符串 packed_ip 不是指定地址族的正确长度,则会引发 ValueError。 调用 inet_ntop() 时出现的错误会引发 socket.error

可用性:Unix(可能不是所有平台)。

2.3 版中的新功能。

socket.getdefaulttimeout()

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

2.3 版中的新功能。

socket.setdefaulttimeout(timeout)

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

2.3 版中的新功能。

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

也可以看看

模块 SocketServer
简化编写网络服务器的类。
模块 ssl
套接字对象的 TLS/SSL 包装器。


17.2.1. 套接字对象

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

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

将套接字绑定到 地址 。 套接字必须尚未绑定。 (address 的格式取决于地址族——见上文。)

笔记

该方法历来接受一对参数用于 AF_INET 地址,而不仅仅是一个元组。 这从来不是故意的,并且在 Python 2.0 及更高版本中不再可用。

socket.close()

关闭插座。 套接字对象上的所有未来操作都将失败。 远程端将不再接收数据(在刷新排队数据后)。 套接字在垃圾收集时会自动关闭。

笔记

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

socket.connect(address)

连接到 地址 处的远程套接字。 (address 的格式取决于地址族——见上文。)

笔记

该方法历来接受一对参数用于 AF_INET 地址,而不仅仅是一个元组。 这从来不是故意的,并且在 Python 2.0 及更高版本中不再可用。

socket.connect_ex(address)

connect(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,则指定用于接收选项的缓冲区的最大长度,并且该缓冲区作为字符串返回。 由调用者来解码缓冲区的内容(请参阅可选的内置模块 struct 以获取解码编码为字符串的 C 结构的方法)。
socket.ioctl(control, option)
平台

窗户

ioctl() 方法是 WSAIoctl 系统接口的受限接口。 请参阅 Win32 文档 了解更多信息。

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

2.6 版中的新功能。

socket.listen(backlog)
侦听与套接字的连接。 backlog 参数指定排队连接的最大数量,并且应该至少为 0; 最大值取决于系统(通常为 5),最小值强制为 0。
socket.makefile([mode[, bufsize]])

返回与套接字关联的 文件对象 。 (文件对象在 File Objects 中描述。)文件对象在其 close() 方法被调用时不会显式关闭套接字,而只是删除它对套接字对象的引用,这样如果没有从其他任何地方引用套接字,它就会关闭。

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

笔记

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

socket.recv(bufsize[, flags])

从套接字接收数据。 返回值是一个表示接收到的数据的字符串。 一次接收的最大数据量由 bufsize 指定。 有关可选参数 flags 的含义,请参见 Unix 手册页 recv(2); 它默认为零。

笔记

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

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

从套接字接收数据,将其写入 buffer 而不是创建新字符串。 返回值是一对 (nbytes, address),其中 nbytes 是接收到的字节数,address 是发送数据的套接字地址。 有关可选参数 flags 的含义,请参见 Unix 手册页 recv(2); 它默认为零。 (address 的格式取决于地址族——见上文。)

2.5 版中的新功能。

socket.recv_into(buffer[, nbytes[, flags]])

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

2.5 版中的新功能。

socket.send(string[, flags])
向套接字发送数据。 套接字必须连接到远程套接字。 可选的 flags 参数与上面的 recv() 具有相同的含义。 返回发送的字节数。 应用程序负责检查所有数据是否已发送; 如果仅传输了部分数据,则应用程序需要尝试传输剩余数据。 有关此概念的更多信息,请参阅 套接字编程 HOWTO
socket.sendall(string[, flags])
向套接字发送数据。 套接字必须连接到远程套接字。 可选的 flags 参数与上面的 recv() 具有相同的含义。 与 send() 不同,此方法继续从 string 发送数据,直到所有数据都已发送或发生错误。 None 成功返回。 出错时,会引发异常,并且无法确定成功发送了多少数据(如果有)。
socket.sendto(string, address)

socket.sendto(string, flags, address)

向套接字发送数据。 套接字不应连接到远程套接字,因为目标套接字由 地址 指定。 可选的 flags 参数与上面的 recv() 具有相同的含义。 返回发送的字节数。 (address 的格式取决于地址族——见上文。)
socket.setblocking(flag)
设置socket的阻塞或非阻塞模式:如果flag为0,则socket设置为非阻塞模式,否则为阻塞模式。 最初所有套接字都处于阻塞模式。 在非阻塞模式下,如果一个 recv() 调用没有找到任何数据,或者如果一个 send() 调用不能立即处理数据,一个 ]error 异常被引发; 在阻塞模式下,调用会阻塞,直到它们可以继续。 s.setblocking(0)相当于s.settimeout(0.0)s.setblocking(1) 相当于 s.settimeout(None)
socket.settimeout(value)

设置阻塞套接字操作的超时时间。 value 参数可以是表示秒的非负浮点数,或 None。 如果给定浮点数,如果超时时间 value 在操作完成之前已经过去,则后续套接字操作将引发 timeout 异常。 将超时设置为 None 会禁用套接字操作的超时。 s.settimeout(0.0)相当于s.setblocking(0)s.settimeout(None) 相当于 s.setblocking(1)

2.3 版中的新功能。

socket.gettimeout()

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

2.3 版中的新功能。

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

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

注意connect()操作需要超时设置,一般情况下建议先调用settimeout()再调用connect()或者pass create_connection() 的超时参数。 无论 Python 套接字超时设置如何,系统网络堆栈都可能返回其自身的连接超时错误。

socket.setsockopt(level, optname, value)
设置给定套接字选项的值(参见 Unix 手册页 setsockopt(2))。 所需的符号常量在 socket 模块(SO_* 等)中定义。 该值可以是表示缓冲区的整数或字符串。 在后一种情况下,由调用者确保字符串包含正确的位(请参阅可选的内置模块 struct 以了解将 C 结构编码为字符串的方法)。
socket.shutdown(how)
关闭连接的一侧或两侧。 如果 howSHUT_RD,则不允许进一步接收。 如果 howSHUT_WR,则不允许进一步发送。 如果 howSHUT_RDWR,则不允许进一步发送和接收。 根据平台的不同,关闭连接的一半也可以关闭另一半(例如 在 Mac OS X 上,shutdown(SHUT_WR) 不允许在连接的另一端进一步读取)。

请注意,没有方法 read()write(); 使用 recv()send() 代替 flags 参数。

Socket 对象还具有这些(只读)属性,这些属性对应于给 socket 构造函数的值。

socket.family

插座家族。

2.5 版中的新功能。

socket.type

插座类型。

2.5 版中的新功能。

socket.proto

套接字协议。

2.5 版中的新功能。


17.2.2. 例子

下面是四个使用 TCP/IP 协议的最小示例程序:一个服务器回显它收到的所有数据(仅服务一个客户端),一个客户端使用它。 请注意,服务器必须执行序列 socket()bind()listen()accept()(可能重复accept() 服务多个客户端),而客户端只需要序列 socket(), connect()。 另请注意,服务器不会在它正在侦听的套接字上 sendall()/recv(),而是在 accept() 返回的新套接字上。

前两个示例仅支持 IPv4。

# Echo server program
import socket

HOST = ''                 # Symbolic name meaning all available interfaces
PORT = 50007              # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
    data = conn.recv(1024)
    if not data: break
    conn.sendall(data)
conn.close()
# Echo client program
import socket

HOST = 'daring.cwi.nl'    # The remote host
PORT = 50007              # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall('Hello, world')
data = s.recv(1024)
s.close()
print 'Received', repr(data)

接下来的两个示例与上述两个示例相同,但同时支持 IPv4 和 IPv6。 服务器端将侦听第一个可用的地址族(它应该同时侦听两者)。 在大多数支持 IPv6 的系统上,IPv6 将优先,服务器可能不接受 IPv4 流量。 客户端将尝试连接到作为名称解析结果返回的所有地址,并将流量发送到第一个连接成功的地址。

# Echo server program
import socket
import sys

HOST = None               # Symbolic name meaning all available interfaces
PORT = 50007              # Arbitrary non-privileged port
s = None
for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC,
                              socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
    af, socktype, proto, canonname, sa = res
    try:
        s = socket.socket(af, socktype, proto)
    except socket.error as msg:
        s = None
        continue
    try:
        s.bind(sa)
        s.listen(1)
    except socket.error as msg:
        s.close()
        s = None
        continue
    break
if s is None:
    print 'could not open socket'
    sys.exit(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
    data = conn.recv(1024)
    if not data: break
    conn.send(data)
conn.close()
# Echo client program
import socket
import sys

HOST = 'daring.cwi.nl'    # The remote host
PORT = 50007              # The same port as used by the server
s = None
for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM):
    af, socktype, proto, canonname, sa = res
    try:
        s = socket.socket(af, socktype, proto)
    except socket.error as msg:
        s = None
        continue
    try:
        s.connect(sa)
    except socket.error as msg:
        s.close()
        s = None
        continue
    break
if s is None:
    print 'could not open socket'
    sys.exit(1)
s.sendall('Hello, world')
data = s.recv(1024)
s.close()
print 'Received', repr(data)

最后一个例子展示了如何在 Windows 上使用原始套接字编写一个非常简单的网络嗅探器。 该示例需要管理员权限才能修改界面:

import socket

# the public network interface
HOST = socket.gethostbyname(socket.gethostname())

# create a raw socket and bind it to the public interface
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
s.bind((HOST, 0))

# Include IP headers
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

# receive all packages
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

# receive a package
print s.recvfrom(65565)

# disabled promiscuous mode
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)

多次运行示例,两次执行之间的延迟太小,可能会导致此错误:

socket.error: [Errno 98] Address already in use

这是因为之前的执行使套接字处于 TIME_WAIT 状态,不能立即重用。

有一个 socket 标志要设置,为了防止这种情况,socket.SO_REUSEADDR

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))

SO_REUSEADDR 标志告诉内核重用处于 TIME_WAIT 状态的本地套接字,而无需等待其自然超时到期。