socket --- socket 模块¶
本模块提供对 BSD socket 接口的访问。
与 CPython 的差异
出于效率和一致性的考虑,MicroPython 中的 socket 对象直接实现了 stream(类文件)接口。在 CPython 中,你需要使用 makefile() 方法将 socket 转换为类文件对象。MicroPython 仍然支持该方法(但它是一个空操作),因此在需要与 CPython 兼容的场合,请务必使用它。
socket 地址格式¶
socket 模块的原生 socket 地址格式是一种由 getaddrinfo() 函数返回的不透明数据类型,必须使用该函数来解析文本地址(包括数字地址):
sockaddr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# You must use getaddrinfo() even for numeric addresses
sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1]
# Now you can use that address
sock.connect(sockaddr)
使用 getaddrinfo() 是处理地址最高效(在内存和处理能力两方面)且最具可移植性的方式。
socket 模块还提供了一种与 CPython 兼容的方式,使用元组来指定地址,如下所述。在 OpenMV Cam 上,socket 模块是内置的;数字地址可以直接以元组格式给出,但域名必须先用 getaddrinfo() 解析。
总结一下:
始终使用
getaddrinfo()来解析主机名。下文所述的元组地址可作为数字地址的快捷写法,用于快速实验和交互式使用。
socket 模块的元组地址格式:
IPv4:(ipv4_address, port),其中 ipv4_address 是采用点分十进制数字表示法的 IPv4 地址字符串,例如
"8.8.8.8",而 port 是 1-65535 范围内的整数端口号。ipv4_address 不接受域名;请先使用getaddrinfo()进行解析。IPv6:(ipv6_address, port, flowinfo, scopeid),其中 ipv6_address 是采用冒号表示法的数字 IPv6 地址字符串,例如
"2001:db8::1",而 port 是 1-65535 范围内的整数端口号。flowinfo 必须为 0。scopeid 是链路本地地址的接口作用域标识符。ipv6_address 不接受域名;请先使用getaddrinfo()进行解析。
函数¶
- socket.getaddrinfo(host: str, port: int, af: int = 0, type: int = 0, proto: int = 0, flags: int = 0, /) List[Tuple]¶
将 host/port 参数转换为一个由 5 元组构成的序列,这些元组包含创建连接到该服务的 socket 所需的全部参数。参数 af、type 和 proto(含义与
socket函数中相同)可用于过滤返回哪类地址。如果某个参数未指定或为零,则可能返回所有地址组合(需要用户侧自行过滤)。得到的 5 元组列表具有以下结构:
(family, type, proto, canonname, sockaddr)下面的示例展示了如何连接到给定的 url:
s = socket.socket() # This assumes that if "type" is not specified, an address for # SOCK_STREAM will be returned, which may be not true s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1])
推荐的过滤参数用法:
s = socket.socket() # Guaranteed to return an address which can be connect'ed to for # stream operation. s.connect(socket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1])
与 CPython 的差异
出错时,CPython 会引发
socket.gaierror异常(OSError的子类)。MicroPython 没有socket.gaierror,而是直接引发 OSError。请注意,getaddrinfo()的错误编号构成一个独立的命名空间,可能与errno模块中的错误编号不一致。为了区分getaddrinfo()的错误,它们用负数表示,而标准系统错误用正数表示(错误编号可通过异常对象的e.args[0]属性获取)。使用负值是一项临时性细节,将来可能会改变。
常量¶
- socket.IPPROTO_IP: int¶
IP 协议层级。与
IP_*选项一起作为 level 参数传给setsockopt()。
- socket.IPPROTO_TCP: int¶
TCP 协议。你不需要将它传给
socket(SOCK_STREAMsocket 类型会自动选定它);它唯一的实际用途是与TCP_*选项一起作为 level 参数传给setsockopt()。
- socket.SOL_SOCKET: int¶
socket 选项层级。与
SO_*选项一起作为 level 参数传给setsockopt()。
- socket.SO_SNDTIMEO: int¶
发送超时,以毫秒为单位,作为 value 参数传给
setsockopt()。
- socket.SO_RCVTIMEO: int¶
接收超时,以毫秒为单位,作为 value 参数传给
setsockopt()。
- socket.IP_ADD_MEMBERSHIP: int¶
加入一个组播组。一个
IPPROTO_IP层级的setsockopt()选项。
- socket.IP_DROP_MEMBERSHIP: int¶
离开一个组播组。一个
IPPROTO_IP层级的setsockopt()选项。
- socket.TCP_NODELAY: int¶
禁用 Nagle 算法。一个
IPPROTO_TCP层级的setsockopt()选项。
- socket.MSG_PEEK: int¶
用于
recv()/recvfrom():返回数据但不将其从输入队列中移除。
- socket.MSG_DONTWAIT: int¶
用于
recv()/recvfrom():以非阻塞模式执行该操作。
类¶
- class socket.socket(af: int = AF_INET, type: int = SOCK_STREAM, proto: int = IPPROTO_TCP, /)¶
使用给定的地址族、socket 类型和协议号创建一个新的 socket。多数情况下无需指定 proto(也不推荐这么做);type 参数会自动选择所需的协议:
# Create STREAM TCP socket socket(AF_INET, SOCK_STREAM) # Create DGRAM UDP socket socket(AF_INET, SOCK_DGRAM)
- close() None¶
将 socket 标记为已关闭并释放所有资源。一旦发生这种情况,对该 socket 对象的所有后续操作都将失败。如果协议支持,远端会收到 EOF 指示。
socket 在被垃圾回收时会自动关闭,但仍建议在使用完毕后立即显式调用
close()将其关闭。
- listen(backlog: int = 2) None¶
让服务器能够接受连接。如果指定了 backlog,则它必须至少为 0(如果小于 0,将被设为 0);它指定了系统在拒绝新连接之前所允许的未接受连接的数量。如果未指定,则会选择一个合理的默认值。
- accept() Tuple['socket', Tuple]¶
接受一个连接。该 socket 必须已绑定到某个地址并正在监听连接。返回值是一个二元组 (conn, address),其中 conn 是一个可用于在该连接上收发数据的新 socket 对象,address 是连接另一端绑定到该 socket 的地址。
- sendall(bytes: bytes) None¶
向 socket 发送全部数据。该 socket 必须已连接到一个远程 socket。与
send()不同,此方法会通过逐块连续发送数据,尝试发送全部数据。此方法在非阻塞 socket 上的行为是未定义的。因此,在 MicroPython 上推荐改用
write()方法,它对阻塞 socket 采用相同的“无短写”策略,并会在非阻塞 socket 上返回已发送的字节数。
- recv(bufsize: int, flags: int = 0) bytes¶
从 socket 接收数据。返回值是一个表示所收到数据的 bytes 对象。单次可接收的最大数据量由 bufsize 指定。
可选的 flags 参数是消息标志(
MSG_PEEK、MSG_DONTWAIT)的按位或,其含义与 CPython 中相同。
- sendto(bytes: bytes, address: Any) int¶
向 socket 发送数据。该 socket 不应连接到远程 socket,因为目标 socket 由 address 指定。
- recvfrom(bufsize: int, flags: int = 0) Tuple[bytes, Tuple]¶
从 socket 接收数据。返回值是一个二元组 (bytes, address),其中 bytes 是表示所收到数据的 bytes 对象,address 是发送该数据的 socket 的地址。
关于可选的 flags 参数的说明,请参见
recv()函数。
- setsockopt(level: int, optname: int, value: int | bytes) None¶
设置给定 socket 选项的值。所需的符号常量定义在 socket 模块中(SO_* 等)。value 可以是一个整数,或一个表示缓冲区的类字节对象。
- settimeout(value: float | None) None¶
为阻塞式 socket 操作设置超时。value 参数可以是表示秒数的非负浮点数,或为 None。如果给出非零值,那么当超时时间在操作完成前已经过去时,后续的 socket 操作将引发
OSError异常。如果给出零,socket 将进入非阻塞模式。如果给出 None,socket 将进入阻塞模式。一种可移植且通用的替代方案是使用
select.poll对象。它允许同时等待多个对象(而且不仅限于 socket,还包括支持轮询的通用 stream 对象)。示例:# Instead of: s.settimeout(1.0) # time in seconds s.read(10) # may timeout # Use: poller = select.poll() poller.register(s, select.POLLIN) res = poller.poll(1000) # time in milliseconds if not res: # s is still not ready for input, i.e. operation timed out
与 CPython 的差异
超时时,CPython 会引发
socket.timeout异常,它是OSError的子类。MicroPython 则直接引发 OSError。如果你用except OSError:来捕获该异常,你的代码在 MicroPython 和 CPython 中都能正常工作。
- setblocking(flag: bool) None¶
设置 socket 的阻塞或非阻塞模式:如果 flag 为 false,则将 socket 设为非阻塞,否则设为阻塞模式。
此方法是某些
settimeout()调用的简写:sock.setblocking(True)等价于sock.settimeout(None)sock.setblocking(False)等价于sock.settimeout(0)
- makefile(mode: str = 'rb', buffering: int = 0, /) Any¶
返回一个与该 socket 关联的文件对象。返回的确切类型取决于传给 makefile() 的参数。仅支持二进制模式('rb'、'wb' 和 'rwb')。不支持 CPython 的参数:encoding、errors 和 newline。
与 CPython 的差异
由于 MicroPython 不支持带缓冲的流,buffering 参数的值会被忽略,并被当作 0(无缓冲)处理。
与 CPython 的差异
关闭 makefile() 返回的文件对象“将”同时关闭原始 socket。
- read(size: int | None = None) bytes¶
从 socket 读取至多 size 个字节。返回一个 bytes 对象。如果未给出 size,则会读取 socket 中所有可用数据直至 EOF;因此该方法在 socket 关闭之前不会返回。此函数会尝试读取所请求的全部数据(无“短读”)。不过对于非阻塞 socket 这可能无法做到,那时将返回较少的数据。