tornado.tcpserver — 基于 IOStream 的基础 TCP 服务器

一个非阻塞的单线程 TCP 服务器。

class tornado.tcpserver.TCPServer(ssl_options: Optional[Union[Dict[str, Any], SSLContext]] = None, max_buffer_size: Optional[int] = None, read_chunk_size: Optional[int] = None)[source]

一个非阻塞的单线程 TCP 服务器。

要使用 TCPServer,请定义一个子类,并覆盖 handle_stream 方法。例如,一个简单的回声服务器可以这样定义

from tornado.tcpserver import TCPServer
from tornado.iostream import StreamClosedError

class EchoServer(TCPServer):
    async def handle_stream(self, stream, address):
        while True:
            try:
                data = await stream.read_until(b"\n") await
                stream.write(data)
            except StreamClosedError:
                break

要使该服务器提供 SSL 流量,请使用带有 ssl.SSLContext 对象的 ssl_options 关键字参数发送。为了与旧版本的 Python 兼容,ssl_options 也可能是一个 ssl.SSLContext.wrap_socket 方法的关键字参数字典。

ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_ctx.load_cert_chain(os.path.join(data_dir, "mydomain.crt"),
                        os.path.join(data_dir, "mydomain.key"))
TCPServer(ssl_options=ssl_ctx)

TCPServer 初始化遵循以下三种模式之一

  1. listen: 单进程

    async def main():
        server = TCPServer()
        server.listen(8888)
        await asyncio.Event.wait()
    
    asyncio.run(main())
    

    虽然此示例本身不创建多个进程,但当将 reuse_port=True 参数传递给 listen() 时,您可以多次运行程序以创建多进程服务。

  2. add_sockets: 多进程

    sockets = bind_sockets(8888)
    tornado.process.fork_processes(0)
    async def post_fork_main():
        server = TCPServer()
        server.add_sockets(sockets)
        await asyncio.Event().wait()
    asyncio.run(post_fork_main())
    

    add_sockets 接口更加复杂,但它可以与 tornado.process.fork_processes 一起使用,以运行从单个父进程派生的所有工作进程的多进程服务。add_sockets 也可以在单进程服务器中使用,如果您希望以 bind_sockets 以外的方式创建监听套接字。

    请注意,使用此模式时,在 fork_processes 之前,不能运行任何与事件循环相关的操作。

  3. bind/start: 简单 **已弃用** 的多进程

    server = TCPServer()
    server.bind(8888)
    server.start(0)  # Forks multiple sub-processes
    IOLoop.current().start()
    

    此模式已弃用,因为它需要自 Python 3.10 以来已弃用的 asyncio 模块中的接口。对在 start 方法中创建多个进程的支持将在 Tornado 的未来版本中删除。

3.1 版本新增: The max_buffer_size argument.

5.0 版本变更: The io_loop argument has been removed.

listen(port: int, address: Optional[str] = None, family: AddressFamily = AddressFamily.AF_UNSPEC, backlog: int = 128, flags: Optional[int] = None, reuse_port: bool = False) None[source]

在给定端口上开始接受连接。

此方法可以多次调用以监听多个端口。listen 立即生效;无需之后调用 TCPServer.start。但是,如果事件循环尚未运行,则必须启动它。

所有参数的含义与 tornado.netutil.bind_sockets 中相同。

6.2 版本变更: Added family, backlog, flags, and reuse_port arguments to match tornado.netutil.bind_sockets.

add_sockets(sockets: Iterable[socket]) None[source]

使该服务器开始接受给定套接字上的连接。

sockets 参数是一个套接字对象列表,例如由 bind_sockets 返回的对象列表。 add_sockets 通常与该方法和 tornado.process.fork_processes 结合使用,以提供对多进程服务器初始化的更多控制。

add_socket(socket: socket) None[source]

add_sockets 的单数版本。接受一个单独的套接字对象。

bind(port: int, address: Optional[str] = None, family: AddressFamily = AddressFamily.AF_UNSPEC, backlog: int = 128, flags: Optional[int] = None, reuse_port: bool = False) None[source]

将该服务器绑定到给定地址上的给定端口。

要启动服务器,请调用 start。如果您想在一个进程中运行该服务器,则可以调用 listen 作为 bindstart 调用序列的快捷方式。

地址可以是 IP 地址或主机名。如果它是一个主机名,服务器将监听与该名称关联的所有 IP 地址。地址可以为空字符串或 None,以监听所有可用接口。Family 可以设置为 socket.AF_INETsocket.AF_INET6 以限制为 IPv4 或 IPv6 地址,否则如果可用,两者都将被使用。

backlog 参数与 socket.listen 的含义相同。 reuse_port 参数与 bind_sockets 的含义相同。

start 之前可以多次调用此方法,以监听多个端口或接口。

在版本 4.4 中更改: 添加了 reuse_port 参数。

在版本 6.2 中更改: 添加了 flags 参数以匹配 bind_sockets

自版本 6.2 起已弃用: 使用 listen()add_sockets() 而不是 bind()start()

start(num_processes: Optional[int] = 1, max_restarts: Optional[int] = None) None[source]

IOLoop 中启动该服务器。

默认情况下,我们在当前进程中运行服务器,并且不派生任何额外的子进程。

如果 num_processes 为 None 或 <= 0,我们将检测此机器上可用的核心数量并派生该数量的子进程。如果给出 num_processes 且 > 1,我们将派生该特定数量的子进程。

由于我们使用的是进程而不是线程,因此任何服务器代码之间没有共享内存。

请注意,多个进程与自动加载模块(或 autoreload=True 选项到 tornado.web.Application,该选项在 debug=True 时默认为 True)不兼容。使用多个进程时,在调用 TCPServer.start(n) 之前,不能创建或引用任何 IOLoops。

Windows 上不支持除 1 以外的 num_processes 值。

max_restarts 参数被传递给 fork_processes

在版本 6.0 中更改: 添加了 max_restarts 参数。

自版本 6.2 起已弃用: 使用 listen()add_sockets() 而不是 bind()start()

stop() None[source]

停止监听新连接。

服务器停止后,正在进行的请求可能仍然继续。

handle_stream(stream: IOStream, address: tuple) Optional[Awaitable[None]][source]

覆盖此方法以处理来自传入连接的新的 IOStream

此方法可能是一个协程;如果是,它异步引发的任何异常都将被记录。传入连接的接受不会被此协程阻塞。

如果此 TCPServer 被配置为 SSL,则 handle_stream 可以在 SSL 握手完成之前被调用。如果需要验证客户端证书或使用 NPN/ALPN,请使用 SSLIOStream.wait_for_handshake

在版本 4.2 中更改: 添加了将此方法作为协程的选项。