18.1. socket — 低级网络接口 — Python 文档
18.1. 插座 — 低级网络接口
该模块提供对 BSD socket 接口的访问。 它适用于所有现代 Unix 系统、Windows、MacOS 以及可能的其他平台。
笔记
某些行为可能取决于平台,因为调用的是操作系统套接字 API。
Python 接口是 Unix 系统调用和套接字库接口到 Python 面向对象风格的直接音译:socket() 函数返回一个 socket 对象 ,其方法实现了各种套接字系统调用。 参数类型比 C 接口中的级别更高:与 Python 文件上的 read()
和 write()
操作一样,接收操作的缓冲区分配是自动的,并且缓冲区长度在发送操作中是隐式的。
18.1.1. 插座系列
根据系统和构建选项,此模块支持各种套接字系列。
根据创建套接字对象时指定的地址族自动选择特定套接字对象所需的地址格式。 套接字地址表示如下:
绑定到文件系统节点的 AF_UNIX 套接字的地址表示为字符串,使用文件系统编码和
'surrogateescape'
错误处理程序(请参阅 PEP 383)。 Linux 抽象命名空间中的地址作为 bytes-like object 返回,并带有初始空字节; 请注意,此命名空间中的套接字可以与普通文件系统套接字通信,因此打算在 Linux 上运行的程序可能需要处理这两种类型的地址。 将字符串或字节类对象作为参数传递时,可以将其用于任一类型的地址。
一对
(host, port)
用于 AF_INET 地址族,其中 host 是一个字符串,表示互联网域符号中的主机名,如'daring.cwi.nl'
或IPv4 地址如'100.50.200.5'
和 port 是一个整数。对于 IPv4 地址,接受两种特殊形式而不是主机地址:
代表
INADDR_ANY
,用于绑定所有接口,字符串'<broadcast>'
代表INADDR_BROADCAST
。 此行为与 IPv6 不兼容,因此,如果您打算在 Python 程序中支持 IPv6,则可能需要避免这些行为。
对于 AF_INET6 地址族,使用四元组
(host, port, flowinfo, scopeid)
,其中 flowinfo 和 scopeid 代表sin6_flowinfo
和 [ C 中struct sockaddr_in6
中的 X143X] 成员。 对于 socket 模块方法,为了向后兼容,可以省略 flowinfo 和 scopeid。 但是请注意,省略 scopeid 可能会导致操作范围内的 IPv6 地址出现问题。AF_NETLINK
插槽表示为(pid, groups)
对。使用
AF_TIPC
地址族,仅 Linux 支持 TIPC。 TIPC 是一种开放的、基于非 IP 的网络协议,设计用于集群计算机环境。 地址由元组表示,字段取决于地址类型。 一般元组形式为(addr_type, v1, v2, v3 [, scope])
,其中:addr_type 是
TIPC_ADDR_NAMESEQ
、TIPC_ADDR_NAME
或TIPC_ADDR_ID
之一。scope 是
TIPC_ZONE_SCOPE
、TIPC_CLUSTER_SCOPE
和TIPC_NODE_SCOPE
之一。如果 addr_type 是
TIPC_ADDR_NAME
,那么 v1 是服务器类型,v2 是端口标识符,而 v3 应该为 0。如果 addr_type 是
TIPC_ADDR_NAMESEQ
,则 v1 是服务器类型,v2 是较低的端口号,而 v3是上面的端口号。如果addr_type为
TIPC_ADDR_ID
,则v1为节点,v2为参考,v3需设置到 0。
元组
(interface, )
用于 AF_CAN 地址族,其中 interface 是表示网络接口名称的字符串,如'can0'
。 网络接口名称可用于从该系列的所有网络接口接收数据包。
字符串或元组
(id, unit)
用于PF_SYSTEM
系列的SYSPROTO_CONTROL
协议。 该字符串是使用动态分配 ID 的内核控件的名称。 如果内核控件的 ID 和单元号已知或使用注册 ID,则可以使用元组。3.3 版中的新功能。
AF_BLUETOOTH
支持以下协议和地址格式:BTPROTO_L2CAP
接受(bdaddr, psm)
其中bdaddr
是作为字符串的蓝牙地址,而psm
是一个整数。BTPROTO_RFCOMM
接受(bdaddr, channel)
其中bdaddr
是作为字符串的蓝牙地址,而channel
是一个整数。BTPROTO_HCI
接受(device_id,)
其中device_id
是一个整数或带有接口蓝牙地址的字符串。 (这取决于您的操作系统;NetBSD 和 DragonFlyBSD 需要一个蓝牙地址,而其他一切都需要一个整数。)3.2 版更改: 添加了 NetBSD 和 DragonFlyBSD 支持。
BTPROTO_SCO
接受bdaddr
,其中bdaddr
是一个 bytes 对象,包含字符串格式的蓝牙地址。 (前任。b'12:23:34:45:56:67'
) FreeBSD 不支持此协议。
AF_ALG 是一个基于 Linux 套接字的内核加密接口。 一个算法套接字配置了一个二到四个元素
(type, name [, feat [, mask]])
的元组,其中:type 是字符串形式的算法类型,例如
aead
、hash
、skcipher
或rng
。name 为字符串形式的算法名称和操作方式,例如
sha256
、hmac(sha256)
、cbc(aes)
或drbg_nopr_ctr_aes256
。feat 和 mask 是无符号 32 位整数。
可用性 Linux 2.6.38,某些算法类型需要更新的内核。
3.6 版中的新功能。
AF_PACKET 是直接连接到网络设备的低级接口。 数据包由元组
(ifname, proto[, pkttype[, hatype[, addr]]])
表示,其中:ifname - 指定设备名称的字符串。
proto - 指定以太网协议编号的网络字节顺序整数。
pkttype - 指定数据包类型的可选整数:
PACKET_HOST
(默认值)- 发往本地主机的数据包。PACKET_BROADCAST
- 物理层广播数据包。PACKET_MULTIHOST
- 发送到物理层多播地址的数据包。PACKET_OTHERHOST
- 发送到某个其他主机的数据包,该数据包已被处于混杂模式的设备驱动程序捕获。PACKET_OUTGOING
- 来自本地主机的数据包循环回数据包套接字。
hatype - 指定 ARP 硬件地址类型的可选整数。
addr - 可选的类字节对象,指定硬件物理地址,其解释取决于设备。
如果在 IPv4/v6 套接字地址的 host 部分使用主机名,程序可能会显示不确定性行为,因为 Python 使用从 DNS 解析返回的第一个地址。 套接字地址将以不同的方式解析为实际的 IPv4/v6 地址,具体取决于 DNS 解析和/或主机配置的结果。 对于确定性行为,请在 host 部分使用数字地址。
所有错误都会引发异常。 可以引发无效参数类型和内存不足情况的正常异常; 从 Python 3.3 开始,与套接字或地址语义相关的错误引发 OSError 或其子类之一(它们曾经引发 socket.error)。
通过 setblocking() 支持非阻塞模式。 通过 settimeout() 支持基于超时的泛化。
18.1.2. 模块内容
模块 socket 导出以下元素。
18.1.2.1. 例外
- exception socket.error
OSError 的已弃用别名。
- exception socket.herror
OSError的一个子类,这个异常是针对地址相关的错误引发的,即 对于在 POSIX C API 中使用 h_errno 的函数,包括 gethostbyname_ex() 和 gethostbyaddr()。 伴随的值是一对
(h_errno, string)
表示库调用返回的错误。 h_errno 是一个数值,而 string 表示 h_errno 的描述,由hstrerror()
C 函数返回。在 3.3 版更改: 此类成为 OSError 的子类。
- exception socket.gaierror
OSError 的子类,getaddrinfo() 和 getnameinfo() 为地址相关错误引发此异常。 伴随的值是一对
(error, string)
表示库调用返回的错误。 string 表示 error 的描述,由gai_strerror()
C 函数返回。 数字 error 值将匹配此模块中定义的EAI_*
常量之一。在 3.3 版更改: 此类成为 OSError 的子类。
- exception socket.timeout
OSError 的子类,当套接字发生超时时会引发此异常,该套接字已通过先前调用 settimeout()(或通过 setdefaulttimeout( ))。 伴随的值是一个字符串,其值当前总是“超时”。
在 3.3 版更改: 此类成为 OSError 的子类。
18.1.2.2. 常数
AF_* 和 SOCK_* 常量现在是
AddressFamily
和SocketKind
IntEnum 集合。3.4 版中的新功能。
- socket.AF_UNIX
socket.AF_INET
socket.AF_INET6
- socket.SOCK_STREAM
socket.SOCK_DGRAM
socket.SOCK_RAW
socket.SOCK_RDM
socket.SOCK_SEQPACKET
- 这些常量代表套接字类型,用于 socket() 的第二个参数。 取决于系统,可能有更多常量可用。 (只有 SOCK_STREAM 和 SOCK_DGRAM 似乎通常有用。)
- socket.SOCK_CLOEXEC
socket.SOCK_NONBLOCK 如果定义了这两个常量,则可以与套接字类型结合使用,并允许您以原子方式设置一些标志(从而避免可能的竞争条件和单独调用的需要)。
也可以看看
安全文件描述符处理 以获得更详尽的解释。
可用性:Linux >= 2.6.27。
3.2 版中的新功能。
- SO_*
socket.SOMAXCONN
MSG_*
SOL_*
SCM_*
IPPROTO_*
IPPORT_*
INADDR_*
IP_*
IPV6_*
EAI_*
AI_*
NI_*
TCP_* 这些形式的许多常量,记录在关于套接字和/或 IP 协议的 Unix 文档中,也在套接字模块中定义。 它们通常用于套接字对象的
setsockopt()
和getsockopt()
方法的参数中。 大多数情况下,只定义那些在 Unix 头文件中定义的符号; 对于一些符号,提供了默认值。3.6 版本变更:
SO_DOMAIN
、SO_PROTOCOL
、SO_PEERSEC
、SO_PASSSEC
、TCP_USER_TIMEOUT
、[ X92X] 被添加。在 3.6.5 版更改: 在 Windows 上,如果运行时 Windows 支持,则会出现
TCP_FASTOPEN
、TCP_KEEPCNT
。
- socket.AF_CAN
socket.PF_CAN
SOL_CAN_*
CAN_* Linux 文档中记录的这些形式的许多常量也在 socket 模块中定义。
可用性:Linux >= 2.6.25。
3.3 版中的新功能。
- socket.CAN_BCM
CAN_BCM_* CAN_BCM 属于 CAN 协议族,是广播管理器 (BCM) 协议。 Linux 文档中记录的广播管理器常量也在套接字模块中定义。
可用性:Linux >= 2.6.25。
3.4 版中的新功能。
- socket.CAN_RAW_FD_FRAMES
在 CAN_RAW 套接字中启用 CAN FD 支持。 默认情况下禁用此功能。 这允许您的应用程序发送 CAN 和 CAN FD 帧; 但是,从套接字读取时,您必须同时接受 CAN 和 CAN FD 帧。
该常量记录在 Linux 文档中。
可用性:Linux >= 3.6。
3.5 版中的新功能。
- socket.AF_PACKET
socket.PF_PACKET
PACKET_* Linux 文档中记录的这些形式的许多常量也在 socket 模块中定义。
可用性:Linux >= 2.2。
- socket.AF_RDS
socket.PF_RDS
socket.SOL_RDS
RDS_* Linux 文档中记录的这些形式的许多常量也在 socket 模块中定义。
可用性:Linux >= 2.6.30。
3.3 版中的新功能。
- socket.SIO_RCVALL
socket.SIO_KEEPALIVE_VALS
socket.SIO_LOOPBACK_FAST_PATH
RCVALL_* Windows 的 WSAIoctl() 常量。 这些常量用作套接字对象的 ioctl() 方法的参数。
3.6 版更改:添加了
SIO_LOOPBACK_FAST_PATH
。
- TIPC_*
- TIPC 相关常量,匹配 C 套接字 API 导出的常量。 有关详细信息,请参阅 TIPC 文档。
- socket.AF_ALG
socket.SOL_ALG
ALG_* Linux 内核加密的常量。
可用性:Linux >= 2.6.38。
3.6 版中的新功能。
- socket.AF_LINK
可用性:BSD、OSX。
3.4 版中的新功能。
- socket.has_ipv6
- 此常量包含一个布尔值,指示此平台是否支持 IPv6。
- socket.BDADDR_ANY
socket.BDADDR_LOCAL
- 这些是包含具有特殊含义的蓝牙地址的字符串常量。 例如,BDADDR_ANY 可用于在使用
BTPROTO_RFCOMM
指定绑定套接字时指示任何地址。
- socket.HCI_FILTER
socket.HCI_TIME_STAMP
socket.HCI_DATA_DIR
- 与
BTPROTO_HCI
一起使用。 HCI_FILTER 不适用于 NetBSD 或 DragonFlyBSD。 HCI_TIME_STAMP 和 HCI_DATA_DIR 不适用于 FreeBSD、NetBSD 或 DragonFlyBSD。
18.1.2.3. 职能
18.1.2.3.1。 创建套接字
以下函数都创建了 套接字对象 。
- socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
使用给定的地址族、套接字类型和协议号创建一个新套接字。 地址族应为 AF_INET(默认值)、AF_INET6、AF_UNIX、AF_CAN、AF_PACKET,或AF_RDS。 套接字类型应为 SOCK_STREAM(默认值)、SOCK_DGRAM、SOCK_RAW 或其他
SOCK_
常量之一。 协议编号通常为零且可以省略,或者在地址族为 AF_CAN 的情况下,协议应为CAN_RAW
或 CAN_BCM 之一。 如果指定了 fileno,则忽略其他参数,导致具有指定文件描述符的套接字返回。 与 socket.fromfd() 不同,fileno 将返回相同的套接字而不是重复的套接字。 这可能有助于使用 socket.close() 关闭分离的套接字。新创建的套接字是 不可继承的 。
3.3 版更改: 增加了 AF_CAN 系列。 添加了 AF_RDS 系列。
3.4 版更改: 增加了 CAN_BCM 协议。
3.4 版更改: 返回的套接字现在是不可继承的。
- socket.socketpair([family[, type[, proto]]])
使用给定的地址族、套接字类型和协议号构建一对连接的套接字对象。 地址族、套接字类型和协议编号与上面的 socket() 函数相同。 如果在平台上定义,则默认系列为 AF_UNIX; 否则,默认值为 AF_INET。
新创建的套接字是 不可继承的 。
3.2 版更改: 返回的套接字对象现在支持整个套接字 API,而不是一个子集。
3.4 版更改: 返回的套接字现在不可继承。
3.5 版更改: 添加了 Windows 支持。
- 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,则将使用操作系统默认行为。3.2 版更改:添加了 source_address。
- socket.fromfd(fd, family, type, proto=0)
复制文件描述符 fd(文件对象的
fileno()
方法返回的整数)并根据结果构建套接字对象。 地址族、套接字类型和协议编号与上面的 socket() 函数相同。 文件描述符应该引用一个套接字,但这不会被检查——如果文件描述符无效,对对象的后续操作可能会失败。 此函数很少需要,但可用于获取或设置作为标准输入或输出传递给程序的套接字上的套接字选项(例如由 Unix inet 守护程序启动的服务器)。 假定套接字处于阻塞模式。新创建的套接字是 不可继承的 。
3.4 版更改: 返回的套接字现在是不可继承的。
- socket.fromshare(data)
从 socket.share() 方法获得的数据实例化一个套接字。 假定套接字处于阻塞模式。
可用性:Windows。
3.3 版中的新功能。
- socket.SocketType
- 这是一个表示套接字对象类型的 Python 类型对象。 与
type(socket(...))
相同。
18.1.2.3.2. 其他功能
socket 模块还提供各种与网络相关的服务:
- socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0)
将 host/port 参数转换为 5 元组序列,其中包含创建连接到该服务的套接字所需的所有参数。 host 是一个域名,一个 IPv4/v6 地址的字符串表示或
None
。 port 是字符串服务名称,例如'http'
、数字端口号或None
。 通过将None
作为 host 和 port 的值传递,您可以将NULL
传递给底层 C API。可以选择指定 family、type 和 proto 参数以缩小返回的地址列表。 将零作为每个参数的值传递选择完整范围的结果。 flags 参数可以是
AI_*
常量中的一个或几个,并将影响结果的计算和返回方式。 例如,AI_NUMERICHOST
将禁用域名解析,如果 host 是域名,则会引发错误。该函数返回具有以下结构的 5 元组列表:
(family, type, proto, canonname, sockaddr)
在这些元组中,family、type、proto 都是整数,并打算传递给 socket() 函数。 canonname 将是一个字符串,表示 host 的规范名称,如果
AI_CANONNAME
是 flags 参数的一部分; 否则 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, proto=socket.IPPROTO_TCP) [(<AddressFamily.AF_INET6: 10>, <SocketType.SOCK_STREAM: 1>, 6, '', ('2606:2800:220:1:248:1893:25c8:1946', 80, 0, 0)), (<AddressFamily.AF_INET: 2>, <SocketType.SOCK_STREAM: 1>, 6, '', ('93.184.216.34', 80))]
3.2 版更改: 现在可以使用关键字参数传递参数。
- socket.getfqdn([name])
- 返回 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 解释器当前正在执行的机器的主机名。
注意: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 可以包含字符串端口名称或数字端口号。
- socket.getprotobyname(protocolname)
- 将 Internet 协议名称(例如,
'icmp'
)转换为适合作为(可选)第三个参数传递给 socket() 函数的常量。 这通常只用于以“原始”模式(SOCK_RAW)打开的套接字; 对于普通套接字模式,如果协议省略或为零,则会自动选择正确的协议。
- socket.getservbyname(servicename[, protocolname])
- 将 Internet 服务名称和协议名称转换为该服务的端口号。 可选的协议名称(如果给出)应该是
'tcp'
或'udp'
,否则任何协议都将匹配。
- socket.getservbyport(port[, protocolname])
- 将 Internet 端口号和协议名称转换为该服务的服务名称。 可选的协议名称(如果给出)应该是
'tcp'
或'udp'
,否则任何协议都将匹配。
- 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 地址字符串无效,则会引发 OSError。 请注意,究竟什么有效取决于
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 个字节,则会引发 OSError。 inet_ntoa() 不支持 IPv6,应使用 inet_ntop() 代替 IPv4/v6 双栈支持。
3.5 版更改:现在接受 可写 字节类对象 。
- socket.inet_pton(address_family, ip_string)
将 IP 地址从特定于系列的字符串格式转换为打包的二进制格式。 inet_pton() 在库或网络协议调用类型为
struct in_addr
(类似于 inet_aton())或struct in6_addr
的对象时很有用。address_family 支持的值为 AF_INET 和 AF_INET6。 如果 IP 地址字符串 ip_string 无效,则会引发 OSError。 请注意,究竟什么有效取决于 address_family 的值和
inet_pton()
的底层实现。可用性:Unix(可能不是所有平台)、Windows。
在 3.4 版更改:添加了 Windows 支持
- 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。 OSError 是针对调用 inet_ntop() 的错误引发的。
可用性:Unix(可能不是所有平台)、Windows。
在 3.4 版更改:添加了 Windows 支持
3.5 版更改:现在接受 可写 字节类对象 。
- socket.CMSG_LEN(length)
返回具有给定 长度 的关联数据的辅助数据项的总长度,没有尾随填充。 该值通常可用作 recvmsg() 的缓冲区大小以接收单个辅助数据项,但 RFC 3542 要求便携式应用程序使用 [ 184]CMSG_SPACE() 并因此包含用于填充的空间,即使该项目将是缓冲区中的最后一个。 如果 length 超出允许的值范围,则引发 OverflowError。
可用性:大多数 Unix 平台,可能还有其他平台。
3.3 版中的新功能。
- socket.CMSG_SPACE(length)
返回 recvmsg() 接收带有给定 length 关联数据的辅助数据项以及任何尾随填充所需的缓冲区大小。 接收多个项目所需的缓冲区空间是其相关数据长度的 CMSG_SPACE() 值的总和。 如果 length 超出允许的值范围,则引发 OverflowError。
请注意,某些系统可能支持辅助数据而不提供此功能。 另请注意,使用此函数的结果设置缓冲区大小可能无法精确限制可以接收的辅助数据量,因为附加数据可能能够放入填充区域。
可用性:大多数 Unix 平台,可能还有其他平台。
3.3 版中的新功能。
- socket.getdefaulttimeout()
- 返回新套接字对象的默认超时(以秒为单位)。
None
的值表示新的套接字对象没有超时。 首次导入socket模块时,默认为None
。
- socket.setdefaulttimeout(timeout)
- 为新的套接字对象设置默认超时(以秒为单位)。 首次导入socket模块时,默认为
None
。 有关可能的值及其各自的含义,请参阅 settimeout()。
- socket.sethostname(name)
将机器的主机名设置为 name。 如果您没有足够的权限,这将引发 OSError。
可用性:Unix。
3.3 版中的新功能。
- socket.if_nameindex()
返回网络接口信息(索引整数,名称字符串)元组的列表。 OSError 如果系统调用失败。
可用性:Unix。
3.3 版中的新功能。
- socket.if_nametoindex(if_name)
返回与接口名称对应的网络接口索引号。 OSError 如果不存在具有给定名称的接口。
可用性:Unix。
3.3 版中的新功能。
- socket.if_indextoname(if_index)
返回与接口索引号对应的网络接口名称。 OSError 如果不存在具有给定索引的接口。
可用性:Unix。
3.3 版中的新功能。
18.1.3. 套接字对象
Socket 对象有以下方法。 除了 makefile(),这些对应于适用于套接字的 Unix 系统调用。
- socket.accept()
接受连接。 套接字必须绑定到一个地址并侦听连接。 返回值是一对
(conn, address)
,其中 conn 是一个 new 套接字对象,可用于在连接上发送和接收数据,address 是绑定到连接另一端的套接字的地址。新创建的套接字是 不可继承的 。
3.4 版更改: 套接字现在不可继承。
在 3.5 版更改:如果系统调用被中断并且信号处理程序没有引发异常,该方法现在重试系统调用而不是引发 InterruptedError 异常(参见 ]PEP 475 的基本原理)。
- socket.bind(address)
- 将套接字绑定到 地址 。 套接字必须尚未绑定。 (address 的格式取决于地址族——见上文。)
- socket.close()
标记插座关闭。 底层系统资源(例如 当 makefile() 中的所有文件对象都关闭时,文件描述符)也会关闭。 一旦发生这种情况,套接字对象上的所有未来操作都将失败。 远程端将不再接收数据(在刷新排队数据后)。
套接字在被垃圾收集时会自动关闭,但建议 close() 显式地关闭它们,或者在它们周围使用 with 语句。
在 3.6 版更改:如果在进行底层
close()
调用时发生错误,现在会引发 OSError。笔记
close() 释放与连接关联的资源,但不一定立即关闭连接。 如果您想及时关闭连接,请在 close() 之前调用 shutdown()。
- socket.connect(address)
连接到 地址 处的远程套接字。 (address 的格式取决于地址族——见上文。)
如果连接被信号中断,则该方法等待直到连接完成,或者在超时时引发 socket.timeout,如果信号处理程序没有引发异常并且套接字被阻塞或有暂停。 对于非阻塞套接字,如果连接被信号中断(或信号处理程序引发的异常),则该方法会引发 InterruptedError 异常。
3.5 版更改: 该方法现在等待连接完成,而不是在连接被信号中断时引发 InterruptedError 异常,信号处理程序不会引发异常并且套接字阻塞或超时(请参阅 PEP 475 了解基本原理)。
- socket.connect_ex(address)
- 与
connect(address)
类似,但对于C级connect()
调用返回的错误返回一个错误指示符而不是引发异常(其他问题,例如“找不到主机”,仍然可以引发异常) . 如果操作成功,错误指示符为0
,否则为errno
变量的值。 这对于支持异步连接等很有用。
- socket.detach()
将套接字对象置于关闭状态而不实际关闭底层文件描述符。 文件描述符被返回,并可用于其他目的。
3.2 版中的新功能。
- socket.dup()
复制插座。
新创建的套接字是 不可继承的 。
3.4 版更改: 套接字现在不可继承。
- socket.fileno()
返回套接字的文件描述符(一个小整数),失败时返回 -1。 这对 select.select() 很有用。
在 Windows 下,此方法返回的小整数不能用于可以使用文件描述符的地方(例如 os.fdopen())。 Unix 没有这个限制。
- socket.get_inheritable()
获取套接字文件描述符或套接字句柄的 可继承标志 :
True
如果套接字可以在子进程中继承,则False
如果不能。3.4 版中的新功能。
- socket.getpeername()
- 返回套接字连接到的远程地址。 例如,这对于找出远程 IPv4/v6 套接字的端口号很有用。 (返回的地址格式取决于地址族——见上文。)在某些系统上不支持此功能。
- socket.getsockname()
- 返回套接字自己的地址。 例如,这对于找出 IPv4/v6 套接字的端口号很有用。 (返回的地址格式取决于地址族——见上文。)
- socket.getsockopt(level, optname[, buflen])
- 返回给定套接字选项的值(参见 Unix 手册页 getsockopt(2))。 所需的符号常量(
SO_*
等)在此模块中定义。 如果 buflen 不存在,则假定为整数选项,并由函数返回其整数值。 如果存在 buflen,则它指定用于接收选项的缓冲区的最大长度,并且该缓冲区作为字节对象返回。 由调用者来解码缓冲区的内容(有关解码编码为字节字符串的 C 结构的方法,请参阅可选的内置模块 struct)。
- socket.gettimeout()
- 返回与套接字操作关联的超时(以秒为单位),如果未设置超时,则返回
None
。 这反映了对 setblocking() 或 settimeout() 的最后一次调用。
- socket.ioctl(control, option)
- 平台
视窗
ioctl() 方法是 WSAIoctl 系统接口的受限接口。 请参阅 Win32 文档 了解更多信息。
在其他平台上,可以使用通用的 fcntl.fcntl() 和 fcntl.ioctl() 函数; 他们接受一个套接字对象作为他们的第一个参数。
目前仅支持以下控制码:
SIO_RCVALL
、SIO_KEEPALIVE_VALS
和SIO_LOOPBACK_FAST_PATH
。3.6 版更改:添加了
SIO_LOOPBACK_FAST_PATH
。
- socket.listen([backlog])
启用服务器以接受连接。 如果指定了backlog,则必须至少为0(如果更低,则设置为0); 它指定系统在拒绝新连接之前允许的未接受连接数。 如果未指定,则选择默认的合理值。
3.5 版更改: backlog 参数现在是可选的。
- socket.makefile(mode='r', buffering=None, *, encoding=None, errors=None, newline=None)
返回与套接字关联的 文件对象 。 确切的返回类型取决于给 makefile() 的参数。 这些参数的解释方式与内置 open() 函数的解释方式相同,除了唯一支持的 mode 值为
'r'
(默认)、'w'
和'b'
。套接字必须处于阻塞模式; 它可以有超时,但如果发生超时,文件对象的内部缓冲区可能会以不一致的状态结束。
关闭由 makefile() 返回的文件对象不会关闭原始套接字,除非所有其他文件对象都已关闭并且 socket.close() 已在套接字对象上调用。
笔记
在 Windows 上,makefile() 创建的类文件对象不能用于需要带有文件描述符的文件对象,例如 subprocess.Popen() 的流参数.
- socket.recv(bufsize[, flags])
从套接字接收数据。 返回值是一个字节对象,表示接收到的数据。 一次接收的最大数据量由 bufsize 指定。 有关可选参数 flags 的含义,请参见 Unix 手册页 recv(2); 它默认为零。
笔记
为了与硬件和网络现实最佳匹配,bufsize 的值应该是相对较小的 2 次幂,例如 4096。
在 3.5 版更改:如果系统调用被中断并且信号处理程序没有引发异常,该方法现在重试系统调用而不是引发 InterruptedError 异常(参见 ]PEP 475 的基本原理)。
- socket.recvfrom(bufsize[, flags])
从套接字接收数据。 返回值是一对
(bytes, address)
,其中 bytes 是表示接收到的数据的字节对象,address 是发送数据的套接字的地址。 有关可选参数 flags 的含义,请参见 Unix 手册页 recv(2); 它默认为零。 (address 的格式取决于地址族——见上文。)在 3.5 版更改:如果系统调用被中断并且信号处理程序没有引发异常,该方法现在重试系统调用而不是引发 InterruptedError 异常(参见 ]PEP 475 的基本原理)。
- socket.recvmsg(bufsize[, ancbufsize[, flags]])
从套接字接收正常数据(最多 bufsize 字节)和辅助数据。 ancbufsize 参数设置用于接收辅助数据的内部缓冲区的大小(以字节为单位); 它默认为 0,意味着不会收到任何辅助数据。 可以使用 CMSG_SPACE() 或 CMSG_LEN() 计算辅助数据的适当缓冲区大小,不适合缓冲区的项目可能会被截断或丢弃。 flags 参数默认为 0,其含义与 recv() 相同。
返回值是一个 4 元组:
(data, ancdata, msg_flags, address)
。 data 项是一个 bytes 对象,保存接收到的非辅助数据。 ancdata 项是零个或多个元组(cmsg_level, cmsg_type, cmsg_data)
的列表,表示接收到的辅助数据(控制消息):cmsg_level 和 cmsg_type 是整数分别指定协议级别和协议特定类型,cmsg_data 是一个 bytes 对象,保存相关数据。 msg_flags项是表示接收消息条件的各种标志的按位或; 有关详细信息,请参阅您的系统文档。 如果接收套接字未连接,则 address 是发送套接字的地址(如果可用); 否则,它的值是未指定的。在某些系统上,sendmsg() 和 recvmsg() 可用于通过 AF_UNIX 套接字在进程之间传递文件描述符。 使用此功能时(通常仅限于 SOCK_STREAM 套接字),recvmsg() 将在其辅助数据中返回形式为
(socket.SOL_SOCKET, socket.SCM_RIGHTS, fds)
的项目,其中fds 是一个 bytes 对象,将新文件描述符表示为原生 Cint
类型的二进制数组。 如果 recvmsg() 在系统调用返回后引发异常,它将首先尝试关闭通过此机制接收到的任何文件描述符。一些系统不指示仅部分接收的辅助数据项的截断长度。 如果一个项目似乎超出了缓冲区的末尾,recvmsg() 将发出 RuntimeWarning,并返回它在缓冲区内的部分,前提是它没有被在其关联数据开始之前被截断。
在支持
SCM_RIGHTS
机制的系统上,以下函数将接收最多 maxfds 个文件描述符,返回消息数据和包含描述符的列表(同时忽略不相关的控制消息等意外情况收到)。 另见sendmsg()。import socket, array def recv_fds(sock, msglen, maxfds): fds = array.array("i") # Array of ints msg, ancdata, flags, addr = sock.recvmsg(msglen, socket.CMSG_LEN(maxfds * fds.itemsize)) for cmsg_level, cmsg_type, cmsg_data in ancdata: if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): # Append data, ignoring any truncated integers at the end. fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) return msg, list(fds)
可用性:大多数 Unix 平台,可能还有其他平台。
3.3 版中的新功能。
在 3.5 版更改:如果系统调用被中断并且信号处理程序没有引发异常,该方法现在重试系统调用而不是引发 InterruptedError 异常(参见 ]PEP 475 的基本原理)。
- socket.recvmsg_into(buffers[, ancbufsize[, flags]])
从套接字接收正常数据和辅助数据,行为与 recvmsg() 一样,但将非辅助数据分散到一系列缓冲区中,而不是返回新的字节对象。 buffers 参数必须是导出可写缓冲区的对象的可迭代对象(例如 bytearray 对象); 这些将被连续的非辅助数据块填充,直到它被全部写入或没有更多的缓冲区。 操作系统可能会对可以使用的缓冲区数量设置限制(sysconf() 值
SC_IOV_MAX
)。 ancbufsize 和 flags 参数与 recvmsg() 的含义相同。返回值是一个 4 元组:
(nbytes, ancdata, msg_flags, address)
,其中 nbytes 是写入缓冲区的非辅助数据的总字节数,ancdata,[ X163X]msg_flags 和 address 与 recvmsg() 相同。例子:
>>> import socket >>> s1, s2 = socket.socketpair() >>> b1 = bytearray(b'----') >>> b2 = bytearray(b'0123456789') >>> b3 = bytearray(b'--------------') >>> s1.send(b'Mary had a little lamb') 22 >>> s2.recvmsg_into([b1, memoryview(b2)[2:9], b3]) (22, [], 0, None) >>> [b1, b2, b3] [bytearray(b'Mary'), bytearray(b'01 had a 9'), bytearray(b'little lamb---')]
可用性:大多数 Unix 平台,可能还有其他平台。
3.3 版中的新功能。
- socket.recvfrom_into(buffer[, nbytes[, flags]])
- 从套接字接收数据,将其写入 buffer 而不是创建新的字节串。 返回值是一对
(nbytes, address)
,其中 nbytes 是接收到的字节数,address 是发送数据的套接字地址。 有关可选参数 flags 的含义,请参见 Unix 手册页 recv(2); 它默认为零。 (address 的格式取决于地址族——见上文。)
- socket.recv_into(buffer[, nbytes[, flags]])
- 从套接字接收最多 nbytes 个字节,将数据存储到缓冲区而不是创建新的字节串。 如果未指定 nbytes(或 0),则最多接收给定缓冲区中可用的大小。 返回接收到的字节数。 有关可选参数 flags 的含义,请参见 Unix 手册页 recv(2); 它默认为零。
- socket.send(bytes[, flags])
向套接字发送数据。 套接字必须连接到远程套接字。 可选的 flags 参数与上面的 recv() 具有相同的含义。 返回发送的字节数。 应用程序负责检查所有数据是否已发送; 如果仅传输了部分数据,则应用程序需要尝试传输剩余数据。 有关此主题的更多信息,请参阅 套接字编程 HOWTO 。
在 3.5 版更改:如果系统调用被中断并且信号处理程序没有引发异常,该方法现在重试系统调用而不是引发 InterruptedError 异常(参见 ]PEP 475 的基本原理)。
- socket.sendall(bytes[, flags])
向套接字发送数据。 套接字必须连接到远程套接字。 可选的 flags 参数与上面的 recv() 具有相同的含义。 与 send() 不同,此方法继续从 bytes 发送数据,直到所有数据都已发送或发生错误。
None
成功返回。 出错时,会引发异常,并且无法确定成功发送了多少数据(如果有)。在 3.5 版更改: 每次成功发送数据时不再重置套接字超时。 套接字超时现在是发送所有数据的最大总持续时间。
在 3.5 版更改:如果系统调用被中断并且信号处理程序没有引发异常,该方法现在重试系统调用而不是引发 InterruptedError 异常(参见 ]PEP 475 的基本原理)。
- socket.sendto(bytes, address)
socket.sendto(bytes, flags, address) 向套接字发送数据。 套接字不应连接到远程套接字,因为目标套接字由 address 指定。 可选的 flags 参数与上面的 recv() 具有相同的含义。 返回发送的字节数。 (address 的格式取决于地址族——见上文。)
在 3.5 版更改:如果系统调用被中断并且信号处理程序没有引发异常,该方法现在重试系统调用而不是引发 InterruptedError 异常(参见 ]PEP 475 的基本原理)。
- socket.sendmsg(buffers[, ancdata[, flags[, address]]])
将正常和辅助数据发送到套接字,从一系列缓冲区中收集非辅助数据并将其连接成单个消息。 buffers 参数将非辅助数据指定为 字节类对象 的可迭代对象(例如 bytes 对象); 操作系统可能会对可以使用的缓冲区数量设置限制(sysconf() 值
SC_IOV_MAX
)。 ancdata 参数将辅助数据(控制消息)指定为可迭代的零个或多个元组(cmsg_level, cmsg_type, cmsg_data)
,其中 cmsg_level 和 cmsg_type 是整数分别指定协议级别和协议特定类型,cmsg_data 是一个类似字节的对象,保存相关数据。 请注意,某些系统(特别是没有 CMSG_SPACE() 的系统)可能支持每次调用仅发送一个控制消息。 flags 参数默认为 0,其含义与 send() 相同。 如果提供了 address 而不是None
,它会设置消息的目标地址。 返回值是发送的非辅助数据的字节数。以下函数在支持
SCM_RIGHTS
机制的系统上通过 AF_UNIX 套接字发送文件描述符列表 fds。 另见recvmsg()。import socket, array def send_fds(sock, msg, fds): return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", fds))])
可用性:大多数 Unix 平台,可能还有其他平台。
3.3 版中的新功能。
在 3.5 版更改:如果系统调用被中断并且信号处理程序没有引发异常,该方法现在重试系统调用而不是引发 InterruptedError 异常(参见 ]PEP 475 的基本原理)。
- socket.sendmsg_afalg([msg, ]*, op[, iv[, assoclen[, flags]]])
sendmsg() 的特殊版本,用于 AF_ALG 套接字。 设置 AF_ALG 套接字的模式、IV、AEAD 相关数据长度和标志。
可用性:Linux >= 2.6.38
3.6 版中的新功能。
- socket.sendfile(file, offset=0, count=None)
使用高性能 os.sendfile 发送文件直到到达 EOF 并返回已发送的总字节数。 file 必须是以二进制模式打开的常规文件对象。 如果 os.sendfile 不可用(例如 Windows) 或 file 不是常规文件 send() 将被使用。 offset 告诉从哪里开始读取文件。 如果指定,count 是要传输的总字节数,而不是在到达 EOF 之前发送文件。 文件位置在返回时更新,或者在错误的情况下更新,在这种情况下 file.tell() 可用于计算发送的字节数。 套接字必须是 SOCK_STREAM 类型。 不支持非阻塞套接字。
3.5 版中的新功能。
- socket.set_inheritable(inheritable)
设置套接字文件描述符或套接字句柄的 可继承标志 。
3.4 版中的新功能。
- socket.setblocking(flag)
设置套接字的阻塞或非阻塞模式:如果 flag 为 false,则套接字设置为非阻塞,否则为阻塞模式。
此方法是某些 settimeout() 调用的简写:
sock.setblocking(True)
相当于sock.settimeout(None)
sock.setblocking(False)
相当于sock.settimeout(0.0)
- socket.settimeout(value)
设置阻塞套接字操作的超时时间。 value 参数可以是表示秒的非负浮点数,或
None
。 如果给出了一个非零值,如果在操作完成之前超时时间 value 已经过去,则后续的套接字操作将引发 timeout 异常。 如果给出零,则套接字处于非阻塞模式。 如果给出None
,则套接字处于阻塞模式。有关更多信息,请参阅有关套接字超时 的 注释。
- socket.setsockopt(level, optname, value: int)
- socket.setsockopt(level, optname, value: buffer)
- socket.setsockopt(level, optname, None, optlen: int)
设置给定套接字选项的值(参见 Unix 手册页 setsockopt(2))。 所需的符号常量在 socket 模块(
SO_*
等)中定义。 该值可以是整数、None
或表示缓冲区的 字节类对象 。 在后一种情况下,由调用者确保字节串包含正确的位(有关将 C 结构编码为字节串的方法,请参阅可选的内置模块 struct)。 当 value 设置为None
时,需要 optlen 参数。 它等效于使用 optval=NULL 和 optlen=optlen 调用 setsockopt C 函数。3.5 版更改:现在接受 可写 字节类对象 。
在 3.6 版更改: 增加了 setsockopt(level, optname, None, optlen: int) 形式。
- socket.shutdown(how)
- 关闭连接的一侧或两侧。 如果 how 是
SHUT_RD
,则不允许进一步接收。 如果 how 是SHUT_WR
,则不允许进一步发送。 如果 how 是SHUT_RDWR
,则不允许进一步发送和接收。
- socket.share(process_id)
复制套接字并准备与目标进程共享。 目标进程必须提供 process_id。 然后可以使用某种形式的进程间通信将生成的字节对象传递给目标进程,并且可以使用 fromshare() 在那里重新创建套接字。 调用此方法后,关闭套接字是安全的,因为操作系统已经为目标进程复制了它。
可用性:Windows。
3.3 版中的新功能。
请注意,没有方法 read()
或 write()
; 使用 recv() 和 send() 代替 flags 参数。
Socket 对象还具有这些(只读)属性,这些属性对应于赋予 socket 构造函数的值。
- socket.family
- 插座家族。
- socket.type
- 插座类型。
- socket.proto
- 套接字协议。
18.1.4. 关于套接字超时的注意事项
套接字对象可以处于以下三种模式之一:阻塞、非阻塞或超时。 默认情况下,套接字总是以阻塞模式创建,但这可以通过调用 setdefaulttimeout() 来更改。
- 在阻塞模式中,操作阻塞直到完成或系统返回错误(如连接超时)。
- 在 非阻塞模式 中,如果操作不能立即完成,则操作将失败(不幸的是系统相关的错误):来自 select 的函数可用于知道何时以及是否一个套接字可用于读取或写入。
- 在 超时模式 中,如果操作无法在为套接字指定的超时内完成(它们引发 timeout 异常)或系统返回错误,则会失败。
笔记
在操作系统层面,超时模式中的套接字在内部设置为非阻塞模式。 此外,阻塞和超时模式在引用同一网络端点的文件描述符和套接字对象之间共享。 这个实现细节可能会产生明显的后果,例如 您决定使用套接字的 fileno()。
18.1.4.1. 超时和connect方法
connect()操作也受超时设置的影响,一般情况下建议在调用connect()之前先调用settimeout()或者传递一个create_connection() 的超时参数。 但是,无论 Python 套接字超时设置如何,系统网络堆栈也可能返回其自身的连接超时错误。
18.1.4.2. 超时和accept方法
如果 getdefaulttimeout() 不是 None,则 accept() 方法返回的套接字继承该超时。 否则,行为取决于侦听套接字的设置:
- 如果监听套接字处于阻塞模式或超时模式,则accept()返回的套接字处于阻塞模式;
- 如果侦听套接字处于 非阻塞模式 ,则 accept() 返回的套接字是处于阻塞模式还是非阻塞模式取决于操作系统。 如果您想确保跨平台行为,建议您手动覆盖此设置。
18.1.5. 例子
下面是四个使用 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
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(data)
# Echo client program
import socket
HOST = 'daring.cwi.nl' # The remote host
PORT = 50007 # The same port as used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
data = s.recv(1024)
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 OSError as msg:
s = None
continue
try:
s.bind(sa)
s.listen(1)
except OSError as msg:
s.close()
s = None
continue
break
if s is None:
print('could not open socket')
sys.exit(1)
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data: break
conn.send(data)
# 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 OSError as msg:
s = None
continue
try:
s.connect(sa)
except OSError as msg:
s.close()
s = None
continue
break
if s is None:
print('could not open socket')
sys.exit(1)
with s:
s.sendall(b'Hello, world')
data = s.recv(1024)
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)
最后一个示例展示了如何使用套接字接口通过原始套接字协议与 CAN 网络进行通信。 要将 CAN 与广播管理器协议一起使用,请使用以下命令打开套接字:
socket.socket(socket.AF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM)
绑定(CAN_RAW
)或连接(CAN_BCM)socket后,可以使用socket.send()和socket.recv() 像往常一样对套接字对象进行操作(及其对应项)。
此示例可能需要特殊权限:
import socket
import struct
# CAN frame packing/unpacking (see 'struct can_frame' in <linux/can.h>)
can_frame_fmt = "=IB3x8s"
can_frame_size = struct.calcsize(can_frame_fmt)
def build_can_frame(can_id, data):
can_dlc = len(data)
data = data.ljust(8, b'\x00')
return struct.pack(can_frame_fmt, can_id, can_dlc, data)
def dissect_can_frame(frame):
can_id, can_dlc, data = struct.unpack(can_frame_fmt, frame)
return (can_id, can_dlc, data[:can_dlc])
# create a raw socket and bind it to the 'vcan0' interface
s = socket.socket(socket.AF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
s.bind(('vcan0',))
while True:
cf, addr = s.recvfrom(can_frame_size)
print('Received: can_id=%x, can_dlc=%x, data=%s' % dissect_can_frame(cf))
try:
s.send(cf)
except OSError:
print('Error sending CAN frame')
try:
s.send(build_can_frame(0x01, b'\x01\x02\x03'))
except OSError:
print('Error sending CAN frame')
多次运行示例,两次执行之间的延迟太小,可能会导致此错误:
OSError: [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
状态的本地套接字,而无需等待其自然超时到期。
也可以看看
有关套接字编程(在 C 中)的介绍,请参阅以下论文:
- 介绍性 4.3BSD 进程间通信教程 ,作者 Stuart Sechrest
- 高级 4.3BSD 进程间通信教程 ,作者:Samuel J。 莱夫勒等人,
均在 UNIX 程序员手册,补充文档 1(PS1:7 和 PS1:8 部分)中。 各种与套接字相关的系统调用的特定于平台的参考资料也是有关套接字语义细节的宝贵信息来源。 对于 Unix,请参阅手册页; 对于 Windows,请参阅 WinSock(或 Winsock 2)规范。 对于支持 IPv6 的 API,读者可能需要参考 RFC 3493 标题为 IPv6 的基本套接字接口扩展。