Python Tornado入门教程 Tornado 方便的非阻塞套接字包装器

2024-02-25 开发教程 Python Tornado入门教程 匿名 0

用于写入和读取非阻塞文件和套接字的实用程序类。

主要有:

BaseIOStream​:用于读写的通用接口。

IOStream​:使用非阻塞套接字实现 BaseIOStream。

SSLIOStream​:支持 SSL 的 IOStream 版本。

PipeIOStream​:基于管道的 IOStream 实现。

基本内容

class tornado.iostream.BaseIOStream(max_buffer_size: Optional[int] = None, read_chunk_size: Optional[int] = None, max_write_buffer_size: Optional[int] = None)

用于写入和读取非阻塞文件或套接字的实用程序类。

我们支持非阻塞 ​write()​ 和一系列 ​read_*()​ 方法。操作完成后,​Awaitable将解析为读取的数据(或 ​None用于 ​write()​)。当流关闭时,所有未完成的 ​Awaitables将使用 ​StreamClosedError解决;BaseIOStream.set_close_callback也可用于通知关闭的流。

当流因错误而关闭时,​IOStream的错误属性包含异常对象。

子类必须实现 ​fileno​、​close_fd​、​write_to_fd​、​read_from_fd和可选的 ​get_fd_error

BaseIOStream构造函数。

参数:

max_buffer_size– 要缓冲的最大传入数据量;默认为 100MB。

read_chunk_size– 一次从底层传输读取的数据量;默认为 64KB。

max_write_buffer_size– 输出到缓冲区的数据量;默认为无限制。

在 4.0 版更改: 添加 ​max_write_buffer_size参数。将默认 ​read_chunk_size更改为 64KB。

在 5.0 版中更改: ​io_loop参数(自 4.1 版以来已弃用)已被删除。

主界面

BaseIOStream.write(data: Union[bytes, memoryview]) → Future[None]

将给定数据异步写入此流。

此方法返回一个 ​Future​,它在写入完成时解析(结果为 ​None​)。

data​参数可以是​bytes​或​memoryview​类型。

在 4.0 版更改: 如果没有给出回调,现在返回 ​Future​。

在 4.5 版更改: 添加了对 ​memoryview参数的支持。

在 6.0 版更改: 回调参数已删除。 改用返回的 ​Future​。

BaseIOStream.read_bytes(num_bytes: int, partial: bool = False) → Awaitable[bytes]

异步读取多个字节。

如果 ​partial为真,只要我们有任何要返回的字节,就会返回数据(但永远不会超过 ​num_bytes​)

在 4.0 版更改: 添加了部分参数。 回调参数现在是可选的,如果省略,将返回 ​Future​。

在 6.0 版更改: ​callback和 ​streaming_callback参数已被删除。 改用返回的 ​Future​(对于 ​streaming_callback​,​partial=True​)。

BaseIOStream.read_into(buf: bytearray, partial: bool = False) → Awaitable[int]

异步读取多个字节。

buf必须是读取数据的可写缓冲区。

如果 ​partial为真,则在读取任何字节后立即运行回调。 否则,当 ​buf完全被读取数据填充时运行。

5.0 版中的新功能。

在 6.0 版更改: 回调参数已删除。 改用返回的Future​。

BaseIOStream.read_until(delimiter: bytes, max_bytes: Optional[int] = None) → Awaitable[bytes]

异步读取,直到我们找到给定的分隔符。

结果包括读取的所有数据,包括分隔符。

如果 ​max_bytes不是 ​None​,如果读取的字节数超过 ​max_bytes并且找不到分隔符,则连接将被关闭。

在 4.0 版更改: 添加了 ​max_bytes参数。 回调参数现在是可选的,如果省略,将返回 ​Future

在 6.0 版更改: 回调参数已删除。 改用返回的 ​Future

BaseIOStream.read_until_regex(regex: bytes, max_bytes: Optional[int] = None) → Awaitable[bytes]

异步读取,直到我们匹配给定的正则表达式。

结果包括与正则表达式匹配的数据以及它之前的任何内容。

如果 ​max_bytes不是 ​None​,如果读取的字节数超过 max_bytes 并且不满足正则表达式,则连接将被关闭。

在 4.0 版更改: 添加了 max_bytes 参数。 回调参数现在是可选的,如果省略,将返回 Future。

在 6.0 版更改: 回调参数已删除。 改用返回的 Future。

BaseIOStream.read_until_close() → Awaitable[bytes]

从套接字异步读取所有数据,直到它关闭。

这将缓冲所有可用数据,直到达到 ​max_buffer_size​。 如果需要流量控制或取消,请使用带有 ​read_bytes(partial=True)​ 的循环。

在 4.0 版更改: 回调参数现在是可选的,如果省略,将返回 ​Future​。

在 6.0 版更改: ​callback和 ​streaming_callback参数已被删除。 改为使用返回的 ​Future​(以及对于 ​streaming_callback的 ​read_bytes和 ​partial=True​)。

BaseIOStream.close(exc_info: Union[None, bool, BaseException, Tuple[Optional[Type[BaseException]], Optional[BaseException], Optional[traceback]]] = False) → None

关闭这个Stream

如果 ​exc_info为真,则将错误属性设置为 ​sys.exc_info​ 中的当前异常(或者如果 ​exc_info是一个元组,则使用它而不是 ​sys.exc_info​)。

BaseIOStream.set_close_callback(callback: Optional[Callable[[], None]]) → None

当Stream关闭时调用给定的回调。

这对于使用 Future 接口的应用程序来说是不必要的; 当Stream关闭时,所有未完成的 Future 都将使用 ​StreamClosedError解决。 但是,它仍然是一种有用的方式来表示流已关闭,而没有其他读取或写入正在进行。

与其他基于回调的接口不同,​set_close_callback在 Tornado 6.0 中没有被移除。

BaseIOStream.closed() → bool

如果Stream已关闭,则返回 ​True

BaseIOStream.reading() → bool

如果我们当前正在从Stream中读取,则返回 ​True

BaseIOStream.writing() → bool

如果我们当前正在写入Stream,则返回 ​True​。

BaseIOStream.set_nodelay(value: bool) → None

为此Stream设置无延迟标志。

默认情况下,写入 TCP Stream的数据可能会保留一段时间,以最有效地利用带宽(根据 Nagle 算法)。 无延迟标志要求尽快写入数据,即使这样做会消耗额外的带宽。

此标志当前仅针对基于 TCP 的 ​IOStream ​定义。

子类的方法

BaseIOStream.fileno() → Union[int, tornado.ioloop._Selectable]

返回此Stream的文件描述符。

BaseIOStream.close_fd() → None

关闭此Stream的基础文件。

close_fd ​由 ​BaseIOStream ​调用,不应在其他地方调用; 其他用户应改为调用 ​close​。

BaseIOStream.write_to_fd(data: memoryview) → int

尝试将数据写入基础文件。

返回写入的字节数。

BaseIOStream.read_from_fd(buf: Union[bytearray, memoryview]) → Optional[int]

尝试从基础文件中读取。

最多读取 ​len(buf)​ 个字节,并将它们存储在缓冲区中。 返回读取的字节数。 如果没有要读取的内容(套接字返回 ​EWOULDBLOCK​ 或等效项),则返回 ​None​,在 ​EOF上返回零。

在 5.0 版更改: 重新设计接口以获取缓冲区并返回多个字节而不是新分配的对象。

BaseIOStream.get_fd_error() → Optional[Exception]

返回有关基础文件上的任何错误的信息。

此方法在 ​IOLoop发出文件描述符上的错误信号后调用,并且应返回异常(例如带有附加信息的 ​socket.error​,如果没有此类信息可用,则返回 ​None​。

实现

class tornado.iostream.IOStream(socket: socket.socket, *args, **kwargs)

基于套接字的 ​IOStream ​实现。

此类支持来自 ​BaseIOStream ​的读取和写入方法以及连接方法。

套接字参数可以是已连接的或未连接的。 对于服务器操作,套接字是调用 ​socket.accept​ 的结果。 对于客户端操作,套接字是使用 ​socket.socket​ 创建的,并且可以在将其传递给 ​IOStream之前进行连接,也可以使用 ​IOStream.connect​ 进行连接。

一个使用此类的非常简单(且损坏)的 HTTP 客户端:

import tornado.ioloop
import tornado.iostream
import socket
async def main():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
stream = tornado.iostream.IOStream(s)
await stream.connect(("friendfeed.com", 80))
await stream.write(b"GET / HTTP/1.0\r\nHost: friendfeed.com\r\n\r\n")
header_data = await stream.read_until(b"\r\n\r\n")
headers = {}
for line in header_data.split(b"\r\n"):
parts = line.split(b":")
if len(parts) == 2:
headers[parts[0].strip()] = parts[1].strip()
body_data = await stream.read_bytes(int(headers[b"Content-Length"]))
print(body_data)
stream.close()
if __name__ == '__main__':
tornado.ioloop.IOLoop.current().run_sync(main)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
stream = tornado.iostream.IOStream(s)
stream.connect(("friendfeed.com", 80), send_request)
tornado.ioloop.IOLoop.current().start()

connect(address: Any, server_hostname: Optional[str] = None) → Future[_IOStreamType]

将套接字连接到远程地址而不阻塞。

仅当传递给构造函数的套接字先前未连接时才可以调用。 ​address参数的格式与 ​socket.connect​ 的格式相同,用于传递给 ​IOStream构造函数的套接字类型,例如 一个​(ip,port)​元组。 此处接受主机名,但将同步解析并阻止 ​IOLoop​。 如果您有主机名而不是 IP 地址,则建议使用 ​TCPClient类而不是直接调用此方法。 ​TCPClient将进行异步 DNS 解析并同时处理 IPv4 和 IPv6。

如果指定了回调,则连接完成时将不带参数调用; 如果不是,则此方法返回一个 Future(成功连接后的结果将是Stream本身)。

在 SSL 模式下,​server_hostname参数将用于证书验证(除非在 ​ssl_options中禁用)和 ​SNI(如果支持;需要 Python 2.7.9+)。

请注意,在连接挂起时调用 ​IOStream.write​ 是安全的,在这种情况下,一旦连接准备好,数据就会被写入。 在连接套接字之前调用 ​IOStream读取方法适用于某些平台,但不可移植。

在 4.0 版更改: 如果没有给出回调,则返回 ​Future​。

在 4.2 版更改:默认情况下验证 SSL 证书; 将 ​ssl_options=dict(cert_reqs=ssl.CERT_NONE)或适当配置的 ​ssl.SSLContext​ 传递给 ​SSLIOStream​ 构造函数以禁用。

在 6.0 版更改: 回调参数已删除。 改用返回的 ​Future​。

start_tls(server_side: bool, ssl_options: Union[Dict[str, Any], ssl.SSLContext, None] = None, server_hostname: Optional[str] = None) → Awaitable[tornado.iostream.SSLIOStream]

将此​IOStream​转换为​SSLIOStream​。

这使得能够在清除文本模式下以清晰文本模式开头的协议,并在一些初始协商后切换到SSL(例如​STARTTLS​扩展到​SMTP​和​IMAP​)。

如果在​Stream​上有未完成的读取或写入,或者如果在​IOStream​的缓冲区中存在任何数据(允许操作系统的套接字缓冲区中的数据),则无法使用此方法。这意味着它通常必须在阅读或写入最后一个清晰文本数据之后立即使用。在任何读取或写入之前,也可以立即使用它。

ssl_options​参数可以是​ssl.slcontext​对象或​ssl.wrap_socket​函数的关键字参数字典。除非在​SSL_Options​中禁用,否则​Server_Hostname​参数将用于证书验证。

此方法返回一个​future​,其结果是新的​SSLIOStream​。在调用此方法后,原始​Stream​上的任何其他操作都未定义。

如果在此​Stream​上定义了关闭回调,则将传输到新​Stream​。

4.0版中的新增功能。

在4.2版中更改:默认情况下验证SSL证书; ​pass ssl_options = dict(cert_reqs = ssl.cert_none)​或适当配置的​ssl.slcontext​禁用。

class tornado.iostream.SSLIOStream(*args, **kwargs)

用于写入和读取非阻塞 SSL 套接字的实用程序类。

如果传递给构造函数的套接字已经连接,则应使用以下内容进行包装:

ssl.wrap_socket(sock, do_handshake_on_connect=False, **kwargs)

在构造 ​SSLIOStream之前。 当 ​IOStream.connect​完成时,未连接的套接字将被包装。

ssl_options关键字参数可以是 ​ssl.SSLContext​ 对象或 ​ssl.wrap_socket​ 的关键字参数字典

wait_for_handshake() → Future[SSLIOStream]

等待初始 SSL 握手完成。

如果给定了回调,则在握手完成后将不带参数地调用它; 否则,此方法返回一个 ​Future​,它将在握手完成后解析为​Stream​本身。

握手完成后,可以在 ​self.socket​ 上访问对等方的证书和 ​NPN/ALPN​ 选择等信息。

此方法旨在用于服务器端​Stream​或使用 ​IOStream.start_tls​ 之后; 它不应该与 ​IOStream.connect​ 一起使用(它已经在等待握手完成)。 每个流只能调用一次。

4.2 版中的新功能。

在 6.0 版更改: 回调参数已删除。 改用返回的 ​Future​。

class tornado.iostream.PipeIOStream(fd: int, *args, **kwargs)

基于管道的 ​IOStream实现。

构造函数采用整数文件描述符(例如 ​os.pipe​ 返回的描述符)而不是打开的文件对象。 管道通常是单向的,因此 ​PipeIOStream可用于读取或写入,但不能同时用于两者。

PipeIOStream仅在基于Unix的平台上可用。

例外

exception tornado.iostream.StreamBufferFullError

缓冲区已满时 ​IOStream方法引发的异常。

exception tornado.iostream.StreamClosedError(real_error: Optional[BaseException] = None)

关闭 ​Stream ​时 ​IOStream ​方法引发的异常。

请注意,关闭回调计划在​Stream​上的其他回调之后运行(以允许处理缓冲数据),因此您可能会在看到关闭回调之前看到此错误。

real_error属性包含导致​Stream​关闭的基础错误(如果有)。

在 4.3 版更改: 添加了 ​real_error属性。

exception tornado.iostream.UnsatisfiableReadError

无法满足读取时引发异常。

由带有 ​max_bytes​参数的 ​read_until和 ​read_until_regex引发。