套接字—低级网络接口

源代码: Lib/socket.py


该模块提供对 BSD * socket *接口的访问。它在所有现代 Unix 系统,Windows,MacOS 以及可能的其他平台上都可用。

Note

由于对 os 套接字 API 进行了调用,因此某些行为可能取决于平台。

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

See also

  • Module socketserver

  • 简化编写 Web Service 器的类。

  • Module ssl

  • 套接字对象的 TLS/SSL 包装器。

Socket families

根据系统和构建选项的不同,此模块支持各种套接字系列。

将根据创建套接字对象时指定的地址系列自动选择特定套接字对象所需的地址格式。套接字地址表示如下:

Note

在版本 3.3 中更改:以前,假定AF_UNIX套接字路径使用 UTF-8 编码。

在版本 3.5 中更改:现在接受可写bytes-like object

在版本 3.7 中更改:对于多播地址(有意义的* scopeid ), address *可能不包含%scope(或zone id)部分。此信息是多余的,可以安全地Ellipsis(推荐)。

如果* addr_type TIPC_ADDR_NAMESEQ,则 v1 为服务器类型, v2 为下端口号, v3 *为上端口号。

如果* addr_type TIPC_ADDR_ID,则 v1 是节点, v2 是引用,并且 v3 *应该设置为 0.

版本 3.3 中的新Function。

在版本 3.2 中更改:添加了 NetBSD 和 DragonFlyBSD 支持。

Availability:Linux 2.6.38,某些算法类型需要更新的内核。

3.6 版的新Function。

Availability:Linux> = 4.8 QEMU> = 2.8 ESX> = 4.0 ESX 工作站> = 6.5.

3.7 版中的新Function。

3.8 版的新Function。

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

所有错误都会引发异常。无效参数类型和内存不足条件的正常异常可以被提出。从 Python 3.3 开始,与套接字或地址语义相关的错误引发OSError或其子类之一(它们用于引发socket.error)。

passsetblocking()支持非阻塞模式。passsettimeout()支持基于超时的通用化。

Module contents

socket模块导出以下元素。

Exceptions

在版本 3.3 中进行了更改:在 PEP 3151之后,该类被命名为OSError

在版本 3.3 中进行了更改:此类已成为OSError的子类。

在版本 3.3 中进行了更改:此类已成为OSError的子类。

在版本 3.3 中进行了更改:此类已成为OSError的子类。

Constants

Note

AF_ *和 SOCK_ *常量现在是AddressFamilySocketKind IntEnum集合。

3.4 版的新Function。

See also

安全文件 Descriptors 处理以获得更详尽的说明。

Availability:Linux> = 2.6.27.

3.2 版中的新Function。

在版本 3.6 中更改:添加了SO_DOMAINSO_PROTOCOLSO_PEERSECSO_PASSSECTCP_USER_TIMEOUTTCP_CONGESTION

在版本 3.6.5 中更改:在 Windows 上,如果运行时 Windows 支持,则显示TCP_FASTOPENTCP_KEEPCNT

在 3.7 版中进行了更改:添加了TCP_NOTSENT_LOWAT

在 Windows 上,如果运行时 Windows 支持,则出现TCP_KEEPIDLETCP_KEEPINTVL

Availability:Linux> = 2.6.25.

版本 3.3 中的新Function。

Availability:Linux> = 2.6.25.

Note

CAN_BCM_CAN_FD_FRAME标志仅在>> 4.8 的 Linux 上可用。

3.4 版的新Function。

该常量在 Linux 文档中有所记录。

Availability:Linux> = 3.6.

3.5 版中的新Function。

Availability:Linux> = 2.6.25.

3.7 版中的新Function。

Availability:Linux> = 2.2.

Availability:Linux> = 2.6.30.

版本 3.3 中的新Function。

在 3.6 版中进行了更改:添加了SIO_LOOPBACK_FAST_PATH

Availability:Linux> = 2.6.38.

3.6 版的新Function。

Availability:Linux> = 4.8.

3.7 版中的新Function。

3.4 版的新Function。

Availability:Linux> = 4.7.

Functions

Creating sockets

以下所有函数均创建socket objects

如果指定了* fileno ,将从指定的文件 Descriptors 中自动检测 family type proto 的值。pass使用显式 family type proto 参数调用该函数,可以否决自动检测。这只会影响 Python 的表示方式返回值socket.getpeername(),但不是实际的 os 资源。与socket.fromfd()不同, fileno *将返回相同的套接字,而不是重复的套接字。这可能有助于使用socket.close()关闭分离的套接字。

新创建的套接字是non-inheritable

用参数selffamilytypeprotocol引发auditing event socket.__new__

在版本 3.3 中更改:添加了 AF_CAN 系列。添加了 AF_RDS 系列。

在版本 3.4 中更改:添加了 CAN_BCM 协议。

在版本 3.4 中进行了更改:现在返回的套接字是不可继承的。

在版本 3.7 中更改:添加了 CAN_ISOTP 协议。

在版本 3.7 中更改:将SOCK_NONBLOCKSOCK_CLOEXEC位标志应用于* type *时,它们将被清除,而socket.type将不反映它们。它们仍然传递给基础系统的 socket()调用。因此,

sock = socket.socket(
    socket.AF_INET,
    socket.SOCK_STREAM | socket.SOCK_NONBLOCK)

仍会在支持SOCK_NONBLOCK的 os 上创建一个非阻塞套接字,但是sock.type将被设置为socket.SOCK_STREAM

新创建的套接字是non-inheritable

在版本 3.2 中进行了更改:现在返回的套接字对象支持整个套接字 API,而不是子集。

在版本 3.4 中进行了更改:现在返回的套接字是不可继承的。

在版本 3.5 中更改:添加了 Windows 支持。

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

如果提供,则* source_address *必须为 2Tuples(host, port),以便套接字在连接之前绑定为其源地址。如果主机或端口分别为''或 0,则将使用 os 默认行为。

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

如果* dualstack_ipv6 为 true 并且平台支持它,则套接字将能够接受 IPv4 和 IPv6 连接,否则它将引发ValueError。大多数 POSIX 平台和 Windows 应该支持此Function。启用此Function后,发生 IPv4 连接时socket.getpeername()返回的地址将是表示为 Map 了 IPv4 的 IPv6 地址的 IPv6 地址。如果 dualstack_ipv6 *为 false,它将在默认情况下在启用该Function的平台上明确禁用此Function(例如 Linux)。该参数可以与has_dualstack_ipv6()结合使用:

import socket

addr = ("", 8080)  # all interfaces, port 8080
if socket.has_dualstack_ipv6():
    s = socket.create_server(addr, family=socket.AF_INET6, dualstack_ipv6=True)
else:
    s = socket.create_server(addr)

Note

在 POSIX 平台上,设置SO_REUSEADDR套接字选项是为了立即重用以前绑定在同一* address *上并保持 TIME_WAIT 状态的套接字。

3.8 版的新Function。

3.8 版的新Function。

新创建的套接字是non-inheritable

在版本 3.4 中进行了更改:现在返回的套接字是不可继承的。

Availability: Windows.

版本 3.3 中的新Function。

Other functions

socket模块还提供各种与网络相关的服务:

3.7 版中的新Function。

可以选择指定* family type proto *参数,以缩小返回的地址列表。为这些参数中的每个参数传递零作为值将选择整个结果范围。 * flags 参数可以是AI_*常量中的一个或多个,并将影响结果的计算和返回方式。例如,AI_NUMERICHOST将禁用域名解析,并且如果 host *为域名,则会引发错误。

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

(family, type, proto, canonname, sockaddr)

在这些 Tuples 中,* family type proto 都是整数,并应传递给socket()函数。如果AI_CANONNAME flags 参数的一部分,则* canonname 将是代表 host 规范名称的字符串;否则 canonname *将为空。 * sockaddr 是一个描述套接字地址的 Tuples,其格式取决于返回的 family *(对于AF_INET(address, port) 2Tuples,对于AF_INET6(address, port, flow info, scope id) 4Tuples),并打算传递给socket.connect()方法。

用参数hostportfamilytypeprotocol引发auditing event socket.getaddrinfo

以下示例为端口 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 中更改:现在可以使用关键字参数传递参数。

在版本 3.7 中更改:对于 IPv6 多播地址,表示地址的字符串将不包含%scope部分。

用参数hostname引发auditing event socket.gethostbyname

用参数hostname引发auditing event socket.gethostbyname

引发不带参数的auditing event socket.gethostname

注意:gethostname()并不总是返回完全限定的域名。为此使用getfqdn()

用参数ip_address引发auditing event socket.gethostbyaddr

对于 IPv6 地址,如果* sockaddr 包含有意义的 scopeid *,则将%scope附加到主机部分。通常,这种情况发生在多播地址上。

有关* flags 的更多信息,请咨询* getnameinfo(3) *。

用参数sockaddr引发auditing event socket.getnameinfo

用参数servicenameprotocolname引发auditing event socket.getservbyname

用参数portprotocolname引发auditing event socket.getservbyport

从 3.7 版开始不推荐使用:如果* x *不适合 16 位无符号整数,但适合正 C int,则将其无声地截断为 16 位无符号整数。不推荐使用此静音截断Function,它将在将来的 Python 版本中引发异常。

从 3.7 版开始不推荐使用:如果* x *不适合 16 位无符号整数,但适合正 C int,则将其无声地截断为 16 位无符号整数。不推荐使用此静音截断Function,它将在将来的 Python 版本中引发异常。

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

如果传递给此Function的 IPv4 地址字符串无效,则将引发OSError。请注意,确切有效的内容取决于inet_aton()的基础 C 实现。

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

如果传递给此函数的字节序列的长度不完全是 4 个字节,则将引发OSErrorinet_ntoa()不支持 IPv6,而应使用inet_ntop()代替 IPv4/v6 双栈。

在版本 3.5 中更改:现在接受可写bytes-like object

Availability:Unix(可能不是所有平台),Windows。

在版本 3.4 中更改:添加了 Windows 支持

Availability:Unix(可能不是所有平台),Windows。

在版本 3.4 中更改:添加了 Windows 支持

在版本 3.5 中更改:现在接受可写bytes-like object

Availability:大多数 Unix 平台,可能还有其他平台。

版本 3.3 中的新Function。

请注意,某些系统可能不提供此Function就支持辅助数据。还应注意,使用此Function的结果来设置缓冲区大小可能不会精确地限制可以接收的辅助数据量,因为其他数据可能会适合填充区域。

Availability:大多数 Unix 平台,可能还有其他平台。

版本 3.3 中的新Function。

用参数name引发auditing event socket.sethostname

Availability: Unix.

版本 3.3 中的新Function。

Availability:Unix,Windows。

版本 3.3 中的新Function。

在 3.8 版中进行了更改:添加了 Windows 支持。

Availability:Unix,Windows。

版本 3.3 中的新Function。

在 3.8 版中进行了更改:添加了 Windows 支持。

Availability:Unix,Windows。

版本 3.3 中的新Function。

在 3.8 版中进行了更改:添加了 Windows 支持。

Socket Objects

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

在版本 3.2 中更改:添加了对context manager协议的支持。退出上下文 Management 器等效于调用close()

新创建的套接字是non-inheritable

在版本 3.4 中进行了更改:套接字现在不可继承。

在版本 3.5 中进行了更改:如果系统调用被break并且 signal 处理程序没有引发异常,则该方法现在重试系统调用,而不是引发InterruptedError异常(有关原理,请参见 PEP 475)。

用参数selfaddress引发auditing event socket.bind

套接字在被垃圾回收时会自动关闭,但是建议显式close()或在它们周围使用with语句。

在版本 3.6 中更改:现在,如果在进行基础close()调用时发生错误,则引发OSError

Note

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

如果连接被 signal break,则该方法将 await 直到连接完成,或者如果 signal 处理程序没有引发异常并且套接字正在阻塞或具有超时,则在超时时引发socket.timeout。对于非阻塞套接字,如果连接被 signal break(或 signal 处理程序引发的异常),则该方法引发InterruptedError异常。

用参数selfaddress引发auditing event socket.connect

在版本 3.5 中进行了更改:现在,该方法将 await 直到连接完成,而不是如果连接被 signal break,signal 处理程序不会引发异常并且套接字正在阻塞或具有超时(请参见),则不会引发InterruptedError异常。 PEP 475)。

用参数selfaddress引发auditing event socket.connect

3.2 版中的新Function。

新创建的套接字是non-inheritable

在版本 3.4 中进行了更改:套接字现在不可继承。

在 Windows 下,不能在可以使用文件 Descriptors 的地方使用此方法返回的小整数(例如os.fdopen())。 Unix 没有此限制。

3.4 版的新Function。

这等效于检查socket.gettimeout() == 0

3.7 版中的新Function。

ioctl()方法是 WSAIoctl 系统接口的受限接口。有关更多信息,请参考Win32 documentation

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

当前仅支持以下控制代码:SIO_RCVALLSIO_KEEPALIVE_VALSSIO_LOOPBACK_FAST_PATH

在 3.6 版中进行了更改:添加了SIO_LOOPBACK_FAST_PATH

在版本 3.5 中进行了更改:* backlog *参数现在是可选的。

套接字必须处于阻止模式;它可能会超时,但是如果发生超时,文件对象的内部缓冲区可能会以不一致的状态结束。

除非所有其他文件对象都已关闭并且在套接字对象上调用了socket.close(),否则关闭makefile()返回的文件对象不会关闭原始套接字。

Note

在 Windows 上,不能在期望带有文件 Descriptors 的文件对象(例如subprocess.Popen()的流参数)使用makefile()创建的类似文件的对象。

Note

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

在版本 3.5 中进行了更改:如果系统调用被break并且 signal 处理程序没有引发异常,则该方法现在重试系统调用,而不是引发InterruptedError异常(有关原理,请参见 PEP 475)。

在版本 3.5 中进行了更改:如果系统调用被break并且 signal 处理程序没有引发异常,则该方法现在重试系统调用,而不是引发InterruptedError异常(有关原理,请参见 PEP 475)。

在版本 3.7 中更改:对于多播 IPv6 地址,地址的第一项不再包含%scope部分。为了获得完整的 IPv6 地址,请使用getnameinfo()

返回值是一个 4Tuples:(data, ancdata, msg_flags, address)。 * data *项目是一个bytes对象,其中包含接收到的非辅助数据。 * ancdata 项目是表示接收到的辅助数据(控制消息)的零个或多个 Tuples(cmsg_level, cmsg_type, cmsg_data)的列表: cmsg_level cmsg_type 是分别指定协议级别和协议特定类型的整数, cmsg_data *是一个bytes对象,包含关联的数据。 * msg_flags 项是指示接收消息条件的各种标志的按位或;有关详细信息,请参见系统文档。如果接收套接字未连接,则 address *是发送套接字的地址(如果有);否则,其值未指定。

在某些系统上,sendmsg()recvmsg()可用于passAF_UNIX套接字在进程之间传递文件 Descriptors。使用此Function时(通常仅限于SOCK_STREAM套接字),recvmsg()将以其辅助数据形式返回(socket.SOL_SOCKET, socket.SCM_RIGHTS, fds)的项目,其中* fds *是bytes对象,该对象将新文件 Descriptors 表示为本机的二进制数组。 C int类型。如果recvmsg()在系统调用返回后引发异常,它将首先try关闭pass此机制接收到的所有文件 Descriptors。

一些系统没有指示仅部分接收到的辅助数据项的截短长度。如果某项似乎超出缓冲区的末尾,则recvmsg()将发出RuntimeWarning,并将返回其在缓冲区内的部分,前提是该项在其关联数据开始之前尚未被截断。

在支持SCM_RIGHTS机制的系统上,以下函数将接收最多* maxfds *个文件 Descriptors,返回消息数据和包含 Descriptors 的列表(同时忽略意外条件,例如接收到无关的控制消息)。另请参见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.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
    return msg, list(fds)

Availability:大多数 Unix 平台,可能还有其他平台。

版本 3.3 中的新Function。

在版本 3.5 中进行了更改:如果系统调用被break并且 signal 处理程序没有引发异常,则该方法现在重试系统调用,而不是引发InterruptedError异常(有关原理,请参见 PEP 475)。

返回值是一个四 Tuples:(nbytes, ancdata, msg_flags, address),其中* nbytes 是写入缓冲区的非辅助数据的字节总数,而 ancdata msg_flags address *与recvmsg()相同。

Example:

>>> 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---')]

Availability:大多数 Unix 平台,可能还有其他平台。

版本 3.3 中的新Function。

在版本 3.5 中进行了更改:如果系统调用被break并且 signal 处理程序没有引发异常,则该方法现在重试系统调用,而不是引发InterruptedError异常(有关原理,请参见 PEP 475)。

在版本 3.5 中进行了更改:每次成功发送数据时,套接字超时都不再重置。现在,套接字超时是发送所有数据的最大总持续时间。

在版本 3.5 中进行了更改:如果系统调用被break并且 signal 处理程序没有引发异常,则该方法现在重试系统调用,而不是引发InterruptedError异常(有关原理,请参见 PEP 475)。

用参数selfaddress引发auditing event socket.sendto

在版本 3.5 中进行了更改:如果系统调用被break并且 signal 处理程序没有引发异常,则该方法现在重试系统调用,而不是引发InterruptedError异常(有关原理,请参见 PEP 475)。

在支持SCM_RIGHTS机制的系统上,以下函数passAF_UNIX套接字发送文件 Descriptors* 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))])

Availability:大多数 Unix 平台,可能还有其他平台。

用参数selfaddress引发auditing event socket.sendmsg

版本 3.3 中的新Function。

在版本 3.5 中进行了更改:如果系统调用被break并且 signal 处理程序没有引发异常,则该方法现在重试系统调用,而不是引发InterruptedError异常(有关原理,请参见 PEP 475)。

Availability:Linux> = 2.6.38.

3.6 版的新Function。

3.5 版中的新Function。

3.4 版的新Function。

此方法是某些settimeout()调用的简写:

在版本 3.7 中更改:该方法不再在socket.type上应用SOCK_NONBLOCK标志。

有关更多信息,请咨询套接字超时注意事项

在版本 3.7 中更改:该方法不再在socket.type上切换SOCK_NONBLOCK标志。

在版本 3.5 中更改:现在接受可写bytes-like object

在版本 3.6 中更改:添加了 setsockopt(level,optname,None,optlen:int)表单。

Availability: Windows.

版本 3.3 中的新Function。

注意,没有方法read()write();请使用不带* flags 参数的recv()send()

套接字对象还具有与赋予socket构造函数的值相对应的这些(只读)属性。

有关套接字超时的说明

套接字对象可以处于以下三种模式之一:阻止,非阻止或超时。默认情况下,套接字始终以阻塞模式创建,但是可以pass调用setdefaulttimeout()来更改。

Note

在 os 级别,处于* timeout 模式*的套接字在内部设置为非阻塞模式。同样,阻塞和超时模式在引用相同网络端点的文件 Descriptors 和套接字对象之间共享。如果,例如,此实施细节可能具有明显的后果。您决定使用套接字的fileno()

超时和连接方法

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

超时和接受方法

如果getdefaulttimeout()不是None,则accept()方法返回的套接字将继承该超时。否则,其行为取决于侦听套接字的设置:

Example

这是使用 TCP/IP 协议的四个最小示例程序:一台服务器,该服务器回显它收到的所有数据(仅为一个 Client 端提供服务),以及一个使用它的 Client 端。请注意,服务器必须执行 Sequencessocket()bind()listen()accept()(可能重复accept()以为多个 Client 端提供服务),而 Client 端仅需要 Sequencessocket()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 流量。Client 端将try连接到由于名称解析而返回的所有地址,并将流量发送到成功连接的第一个地址。

# 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 上使用原始套接字编写一个非常简单的网络嗅探器。该示例需要 Management 员特权才能修改接口:

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)

下一个示例显示如何使用套接字接口pass原始套接字协议与 CAN 网络通信。要将 CAN 与 BroadcastManagement 器协议结合使用,请打开带有以下内容的套接字:

socket.socket(socket.AF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM)

在绑定(CAN_RAW)或连接(CAN_BCM)套接字之后,您可以照常在套接字对象上使用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状态的本地套接字,而不必 await 其自然超时到期。

See also

有关套接字编程(用 C 语言编写)的介绍,请参见以下文章:

    • 4.3 BSD 进程间通信入门指南*,作者:Stuart Sechrest
    • Samuel J.Leffler 等人撰写的高级 4.3BSD 进程间通信教程*,

两者均在 UNIX 程序员手册,补充文档 1(PS1:7 和 PS1:8)中进行。各种与套接字相关的系统调用的特定于平台的参考资料也是有关套接字语义细节的有价值的信息来源。对于 Unix,请参考手册页。对于 Windows,请参阅 WinSock(或 Winsock 2)规范。对于支持 IPv6 的 API,Reader 可能希望参考 RFC 3493标题为 IPv6 的基本套接字接口扩展。

首页