>>> 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.
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,在 IPv4/v6 双协议栈下应使用 inet_pton()
来代替。
socket.
inet_ntoa
(packed_ip)
将 32 位压缩 IPv4 地址(一个 类字节对象,长 4 个字节)转换为标准的点分十进制字符串形式(如 ‘123.45.67.89’ )。与那些使用标准 C 库,且需要 struct in_addr
类型的对象的程序交换信息时,本函数很有用。 该类型即本函数参数中的 32 位压缩二进制数据的 C 类型。
如果传入本函数的字节序列长度不是 4 个字节,则抛出 OSError
。inet_ntoa()
不支持 IPv6,在 IPv4/v6 双协议栈下应使用 inet_ntop()
来代替。
在 3.5 版更改: 现在支持可写的 字节类对象。
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 无效,则抛出 OSError
。注意,具体什么地址有效取决于 address_family 的值和 inet_pton()
的底层实现。
Availability: Unix (maybe not all platforms), Windows.
在 3.4 版更改: 添加了 Windows 支持
socket.
inet_ntop
(address_family, packed_ip)
将压缩 IP 地址(一个 类字节对象,数个字节长)转换为标准的、特定地址簇的字符串形式(如 '7.10.0.5'
或 '5aef:2b::8'
)。当库或网络协议返回 struct in_addr
类型的对象(类似 inet_ntoa()
)或 struct in6_addr
类型的对象时,inet_ntop()
很有用。
目前 address_family 支持 AF_INET
和 AF_INET6
。如果字节对象 packed_ip 与指定的地址簇长度不符,则抛出 ValueError
。针对 inet_ntop()
调用的错误则抛出 OSError
。
Availability: Unix (maybe not all platforms), Windows.
在 3.4 版更改: 添加了 Windows 支持
在 3.5 版更改: 现在支持可写的 字节类对象。
socket.
CMSG_LEN
(length)
返回给定 length 所关联数据的辅助数据项的总长度(不带尾部填充)。此值通常用作 recvmsg()
接收一个辅助数据项的缓冲区大小,但是 RFC 3542 要求可移植应用程序使用 CMSG_SPACE()
,以此将尾部填充的空间计入,即使该项在缓冲区的最后。如果 length 超出允许范围,则抛出 OverflowError
。
Availability: most Unix platforms, possibly others.
3.3 新版功能.
socket.
CMSG_SPACE
(length)
返回 recvmsg()
所需的缓冲区大小,以接收给定 length 所关联数据的辅助数据项,带有尾部填充。接收多个项目所需的缓冲区空间是关联数据长度的 CMSG_SPACE()
值的总和。如果 length 超出允许范围,则抛出 OverflowError
。
请注意,某些系统可能支持辅助数据,但不提供本函数。还需注意,如果使用本函数的结果来设置缓冲区大小,可能无法精确限制可接收的辅助数据量,因为可能会有其他数据写入尾部填充区域。
Availability: most Unix platforms, possibly others.
3.3 新版功能.
socket.
if_nameindex
()
返回一个列表,包含网络接口(网卡)信息二元组(整数索引,名称字符串)。系统调用失败则抛出 OSError
。
Availability: Unix.
3.3 新版功能.
socket.
if_nametoindex
(if_name)
返回网络接口名称相对应的索引号。如果没有所给名称的接口,则抛出 OSError
。
Availability: Unix.
3.3 新版功能.
socket.
if_indextoname
(if_index)
返回网络接口索引号相对应的接口名称。如果没有所给索引号的接口,则抛出 OSError
。
Availability: Unix.
3.3 新版功能.
socket.
accept
()
接受一个连接。此 socket 必须绑定到一个地址上并且监听连接。返回值是一个 (conn, address)
对,其中 conn 是一个 新 的套接字对象,用于在此连接上收发数据,address 是连接另一端的套接字所绑定的地址。
新创建的套接字是 不可继承的。
在 3.4 版更改: 该套接字现在是不可继承的。
在 3.5 版更改: 如果系统调用被中断,但信号处理程序没有触发异常,此方法现在会重试系统调用,而不是触发 InterruptedError
异常 (原因详见 PEP 475)。
socket.
close
()
将套接字标记为关闭。当 makefile()
创建的所有文件对象都关闭时,底层系统资源(如文件描述符)也将关闭。一旦上述情况发生,将来对套接字对象的所有操作都会失败。对端将接收不到任何数据(清空队列数据后)。
垃圾回收时,套接字会自动关闭,但建议显式 close()
它们,或在它们周围使用 with
语句。
close()
释放与连接相关联的资源,但不一定立即关闭连接。如果需要及时关闭连接,请在调用 close()
之前调用 shutdown()
。
socket.
connect
(address)
连接到 address 处的远程套接字。( address 的格式取决于地址簇 —— 参见上文)
如果连接被信号中断,则本方法将等待,直到连接完成。如果信号处理程序未抛出异常,且套接字阻塞中或已超时,则在超时后抛出 socket.timeout
。对于非阻塞套接字,如果连接被信号中断,则本方法将抛出 InterruptedError
异常(或信号处理程序抛出的异常)。
在 3.5 版更改: 本方法现在将等待,直到连接完成,而不是在以下情况抛出 InterruptedError
异常。该情况为,连接被信号中断,信号处理程序未抛出异常,且套接字阻塞中或已超时(具体解释请参阅 PEP 475 )。
socket.
listen
([backlog])
启动一个服务器用于接受连接。如果指定 backlog,则它最低为 0(小于 0 会被置为 0),它指定系统允许暂未 accept 的连接数,超过后将拒绝新连接。未指定则自动设为合理的默认值。
在 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()
中的相同。
返回值是一个四元组: (data, ancdata, msg_flags, address)
。data 项是一个 bytes
对象,用于保存接收到的非辅助数据。ancdata 项是零个或多个元组 (cmsg_level, cmsg_type, cmsg_data)
组成的列表,表示接收到的辅助数据(控制消息):cmsg_level 和 cmsg_type 是分别表示协议级别和协议类型的整数,而 cmsg_data 是保存相关数据的 bytes
对象。msg_flags 项由各种标志按位或组成,表示接收消息的情况,详细信息请参阅系统文档。如果接收端套接字断开连接,则 address 是发送端套接字的地址(如果有),否则该值无指定。
某些系统上可以利用 AF_UNIX
套接字通过 sendmsg()
和 recvmsg()
在进程之间传递文件描述符。使用此功能时(通常仅限于 SOCK_STREAM
套接字),recvmsg()
将在其辅助数据中返回以下格式的项 (socket.SOL_SOCKET, socket.SCM_RIGHTS, fds)
,其中 fds 是一个 bytes
对象,是新文件描述符表示为原生 C int
类型的二进制数组。如果 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)
Availability: most Unix platforms, possibly others.
3.3 新版功能.
在 3.5 版更改: 如果系统调用被中断,但信号处理程序没有触发异常,此方法现在会重试系统调用,而不是触发 InterruptedError
异常 (原因详见 PEP 475)。
socket.
recvmsg_into
(buffers[, ancbufsize[, flags]])
从套接字接收普通数据和辅助数据,其行为与 recvmsg()
相同,但将非辅助数据分散到一系列缓冲区中,而不是返回新的字节对象。buffers 参数必须是可迭代对象,它迭代出可供写入的缓冲区(如 bytearray
对象),这些缓冲区将被连续的非辅助数据块填充,直到数据全部写完或缓冲区用完为止。在允许使用的缓冲区数量上,操作系统可能会有限制( sysconf()
的 SC_IOV_MAX
值)。ancbufsize 和 flags 参数的含义与 recvmsg()
中的相同。
返回值为四元组: (nbytes, ancdata, msg_flags, address)
,其中 nbytes 是写入缓冲区的非辅助数据的字节总数,而 ancdata、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')
>>> 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: most Unix platforms, possibly others.
3.3 新版功能.
socket.
send
(bytes[, flags])
发送数据给套接字。本套接字必须已连接到远程套接字。可选参数 flags 的含义与上述 recv()
中的相同。本方法返回已发送的字节数。应用程序要负责检查所有数据是否已发送,如果仅传输了部分数据,程序需要自行尝试传输其余数据。有关该主题的更多信息,请参考 套接字编程指南。
在 3.5 版更改: 如果系统调用被中断,但信号处理程序没有触发异常,此方法现在会重试系统调用,而不是触发 InterruptedError
异常 (原因详见 PEP 475)。
socket.
sendall
(bytes[, flags])
发送数据给套接字。本套接字必须已连接到远程套接字。可选参数 flags 的含义与上述 recv()
中的相同。与 send()
不同,本方法持续从 bytes 发送数据,直到所有数据都已发送或发生错误为止。成功后会返回 None
。出错后会抛出一个异常,此时并没有办法确定成功发送了多少数据。
在 3.5 版更改: 每次成功发送数据后,套接字超时不再重置。现在,套接字超时是发送所有数据的最大总持续时间。
在 3.5 版更改: 如果系统调用被中断,但信号处理程序没有触发异常,此方法现在会重试系统调用,而不是触发 InterruptedError
异常 (原因详见 PEP 475)。
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))])
Availability: most Unix platforms, possibly others.
3.3 新版功能.
在 3.5 版更改: 如果系统调用被中断,但信号处理程序没有触发异常,此方法现在会重试系统调用,而不是触发 InterruptedError
异常 (原因详见 PEP 475)。
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.
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
异常。如果赋为 0,则套接字将处于非阻塞模式。如果指定为 None
,则套接字将处于阻塞模式。
更多信息请查阅 关于套接字超时的说明。
socket.
setsockopt
(level, optname, value)
Set the value of the given socket option (see the Unix manual page
setsockopt(2)). The needed symbolic constants are defined in the
socket
module (SO_*
etc.). The value can be an integer or
a bytes-like object representing a buffer. In the latter case it is
up to the caller to
ensure that the bytestring contains the proper bits (see the optional built-in
module struct
for a way to encode C structures as bytestrings).
在 3.5 版更改: 现在支持可写的 字节类对象。
socket.
share
(process_id)
复制套接字,并准备将其与目标进程共享。目标进程必须以 process_id 形式提供。然后可以利用某种形式的进程间通信,将返回的字节对象传递给目标进程,还可以使用 fromshare()
在新进程中重新创建套接字。一旦本方法调用完毕,就可以安全地将套接字关闭,因为操作系统已经为目标进程复制了该套接字。
Availability: Windows.
3.3 新版功能.
注意此处没有 read()
或 write()
方法,请使用不带 flags 参数的 recv()
和 send()
来替代。
套接字对象还具有以下(只读)属性,这些属性与传入 socket
构造函数的值相对应。
socket.
family
套接字的协议簇
18.1.4. 关于套接字超时的说明
一个套接字对象可以处于以下三种模式之一:阻塞、非阻塞或超时。套接字默认以阻塞模式创建,但是可以调用 setdefaulttimeout()
来更改。
在 blocking mode (阻塞模式)中,操作将阻塞,直到操作完成或系统返回错误(如连接超时)。
在 non-blocking mode (非阻塞模式)中,如果操作无法立即完成,则操作将失败(不幸的是,不同系统返回的错误不同):位于 select
中的函数可用于了解套接字何时以及是否可以读取或写入。
在 timeout mode (超时模式)下,如果无法在指定的超时内完成操作(抛出 timeout
异常),或如果系统返回错误,则操作将失败。
在操作系统层面上,超时模式 下的套接字在内部都设置为非阻塞模式。同时,阻塞和超时模式在文件描述符和套接字对象之间共享,这些描述符和对象均应指向同一个网络端点。如果,比如你决定使用套接字的 fileno()
,这一实现细节可能导致明显的结果。
18.1.4.1. 超时与 connect
方法
connect()
操作也受超时设置的约束,通常建议在调用 connect()
之前调用 settimeout()
,或将超时参数直接传递给 create_connection()
。但是,无论 Python 套接字超时设置如何,系统网络栈都有可能返回自带的连接超时错误。
18.1.4.2. 超时与 accept
方法
如果 getdefaulttimeout()
的值不是 None
,则 accept()
方法返回的套接字将继承该超时值。若是 None,返回的套接字行为取决于侦听套接字的设置:
如果侦听套接字处于 阻塞模式 或 超时模式,则 accept()
返回的套接字处于 阻塞模式;
如果侦听套接字处于 非阻塞模式,那么 accept()
返回的套接字是阻塞还是非阻塞取决于操作系统。如果要确保跨平台时的正确行为,建议手动覆盖此设置。
18.1.5. 示例
以下是 4 个使用 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)
The last example shows how to use the socket interface to communicate to a CAN
network using the raw socket protocol. To use CAN with the broadcast
manager protocol instead, open a socket with:
socket.socket(socket.AF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM)
在绑定 (CAN_RAW
) 或连接 (CAN_BCM
) socket 之后,你将可以在 socket 对象上正常使用 socket.send()
以及 socket.recv()
操作(及同类操作)。
This example might require special privileges:
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 语言)的介绍,请参阅以下文章:
An Introductory 4.3BSD Interprocess Communication Tutorial,作者 Stuart Sechrest
An Advanced 4.3BSD Interprocess Communication Tutorial,作者 Samuel J. Leffler et al,
两篇文章都在 UNIX 开发者手册,补充文档 1(第 PS1:7 和 PS1:8 节)中。那些特定于平台的参考资料,它们包含与套接字有关的各种系统调用,也是套接字语义细节的宝贵信息来源。对于 Unix,请参考手册页。对于 Windows,请参阅 WinSock(或 Winsock 2)规范。如果需要支持 IPv6 的 API,读者可能希望参考 RFC 3493,标题为 Basic Socket Interface Extensions for IPv6。