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
初始化遵循以下三种模式之一listen
: 单进程async def main(): server = TCPServer() server.listen(8888) await asyncio.Event.wait() asyncio.run(main())
虽然此示例本身不创建多个进程,但当将
reuse_port=True
参数传递给listen()
时,您可以多次运行程序以创建多进程服务。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
之前,不能运行任何与事件循环相关的操作。-
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
, andreuse_port
arguments to matchtornado.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
作为bind
和start
调用序列的快捷方式。地址可以是 IP 地址或主机名。如果它是一个主机名,服务器将监听与该名称关联的所有 IP 地址。地址可以为空字符串或 None,以监听所有可用接口。Family 可以设置为
socket.AF_INET
或socket.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()
。
- handle_stream(stream: IOStream, address: tuple) Optional[Awaitable[None]] [source]¶
覆盖此方法以处理来自传入连接的新的
IOStream
。此方法可能是一个协程;如果是,它异步引发的任何异常都将被记录。传入连接的接受不会被此协程阻塞。
如果此
TCPServer
被配置为 SSL,则handle_stream
可以在 SSL 握手完成之前被调用。如果需要验证客户端证书或使用 NPN/ALPN,请使用SSLIOStream.wait_for_handshake
。在版本 4.2 中更改: 添加了将此方法作为协程的选项。