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)[原始碼]

一個非阻塞、單執行緒的 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_options 關鍵字參數傳送 ssl.SSLContext 物件。 為了與舊版本的 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 一起使用,以執行一個多進程服務,其中所有工作進程都從單個父進程派生。 如果您想以 bind_sockets 以外的方式建立監聽 socket,也可以在單進程伺服器中使用 add_sockets

    請注意,當使用此模式時,任何涉及事件迴圈的操作都不能在 fork_processes 之前執行。

  3. bind/start:簡單的已棄用多進程

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

    此模式已被棄用,因為它需要 asyncio 模組中自 Python 3.10 起已被棄用的介面。 在 start 方法中建立多個進程的支援將在未來版本的 Tornado 中移除。

3.1 版新增: max_buffer_size 引數。

5.0 版變更: 已移除 io_loop 引數。

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

開始在給定的埠上接受連線。

此方法可以多次呼叫,以監聽多個埠。 listen 會立即生效;不需要後續呼叫 TCPServer.start。然而,如果事件迴圈尚未運行,則必須啟動它。

所有引數的意義與 tornado.netutil.bind_sockets 中的相同。

在 6.2 版本變更: 新增了 familybacklogflagsreuse_port 引數,以匹配 tornado.netutil.bind_sockets

add_sockets(sockets: Iterable[socket]) None[原始碼]

使此伺服器開始在給定的 socket 上接受連線。

sockets 參數是 socket 物件的清單,例如由 bind_sockets 回傳的物件。add_sockets 通常與該方法和 tornado.process.fork_processes 結合使用,以提供對多程序伺服器初始化的更大控制。

add_socket(socket: socket) None[原始碼]

add_sockets 的單數版本。 採用單個 socket 物件。

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

將此伺服器繫結到給定位址上的給定埠。

要啟動伺服器,請呼叫 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[原始碼]

IOLoop 中啟動此伺服器。

預設情況下,我們在此程序中執行伺服器,並且不派生任何額外的子程序。

如果 num_processes 為 None 或 <= 0,我們會偵測此機器上可用的核心數量,並派生該數量的子程序。如果給定了 num_processes 且 > 1,我們會派生該特定數量的子程序。

由於我們使用程序而不是執行緒,因此任何伺服器程式碼之間都沒有共享記憶體。

請注意,多個程序與自動重新載入模組(或 tornado.web.Applicationautoreload=True 選項,當 debug=True 時預設為 True)不相容。當使用多個程序時,在呼叫 TCPServer.start(n) 之前,無法建立或參考任何 IOLoop。

Windows 上不支援 1 以外的 num_processes 值。

max_restarts 引數會傳遞給 fork_processes

在 6.0 版本中變更: 新增 max_restarts 引數。

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

stop() None[原始碼]

停止監聽新的連線。

伺服器停止後,目前正在進行的要求可能仍會繼續。

handle_stream(stream: IOStream, address: tuple) Optional[Awaitable[None]][原始碼]

覆寫以處理來自傳入連線的新 IOStream

此方法可以是協程;如果是,它非同步引發的任何例外都會被記錄。傳入連線的接受不會被此協程封鎖。

如果此 TCPServer 設定為 SSL,則可能在 SSL 交握完成之前呼叫 handle_stream。如果您需要驗證用戶端的憑證或使用 NPN/ALPN,請使用 SSLIOStream.wait_for_handshake

在 4.2 版本中變更: 新增此方法為協程的選項。