Tornado websocket 服务器和 websocket 客户端同时在一个循环中使用 AsyncIO

Tornado websocket server and websocket client concurrently in one loop with AsyncIO

我想 运行 一个 tornado websocket 服务器和一个单独的 websocket 客户端同时在同一个循环中,这样我就可以从那个单一的 websocket 客户端接收数据并将它从 tornado 服务器发送到所有连接的客户。

我可以 运行 tornado 服务器,我可以 运行 websocket 客户端,但是 tornado 服务器没有响应客户端请求。我得到类似 "waiting for response from 127.0.0.1:8000".

的东西

我想我遇到了异步问题。我假设我的 websocket 客户端阻止了整个过程...

有人知道吗?

谢谢!

龙卷风服务器:

import os.path
import tornado.web
import tornado.websocket
import tornado.httpserver
import asyncio
from ws_client import WebsocketClient


URL = "ws://echo.websocket.org"
tornado_connections = set()
ws_echo = None

class Application(tornado.web.Application): 
   def __init__(self):
       handlers = [
           (r"/", IndexHandler),
           (r"/ws", WsHandler)
           ]
       settings = dict(
           template_path=os.path.join(os.path.dirname(__file__), "template"), 
           static_path=os.path.join(os.path.dirname(__file__), "static"), 
       )
       tornado.web.Application.__init__(self, handlers, **settings)

class IndexHandler(tornado.web.RequestHandler): 
   def get(self):
       self.render("index_test.html")

class WsHandler(tornado.websocket.WebSocketHandler): 
   async def open(self):
       if self not in tornado_connections:
           await tornado_connections.add(self)
           await ws_echo.update_connections(connections=tornado_connections)
           print('TORNADO: client connected.')

   def on_message(self, message): 
       print(message)

   def on_close(self):
       if self in tornado_connections:
           tornado_connections.remove(self)
           print('TORNADO: client disconnected.')


async def start_tornado_server():
   app = Application()
   server = tornado.httpserver.HTTPServer(app) 
   server.listen(8000)

async def start_ws_client():
   ws_echo = WebsocketClient(url=URL, connections=tornado_connections)
   await ws_echo.connect()

async def main():
   await start_tornado_server()
   asyncio.create_task(start_ws_client())

asyncio.run(main())

Websocket 客户端:

import websocket
import asyncio


class WebsocketClient:
    def __init__(self, url, connections):
        self.url = url
        self.connections = connections

    def __on_open(self):
        print('Echo client connected')
        self.ws.send("Websocket rocks!")

    def __on_message(self, msg):
        print("on_messaeg: ", msg)

    def __on_close(self):
        print("Websocket closed")

    async def connect(self):
        self.ws = websocket.WebSocketApp(
            self.url,
            on_open=self.__on_open,
            on_message=self.__on_message,
            on_close=self.__on_close,
        )
        await self.ws.run_forever()

    async def disconnect(self):
        await self.ws.close()

    async def update_connections(self, connections):
        self.connections = connections
        await print("connections: ", len(self.connections))

JavaScript Websocket 客户端:

var ws = new WebSocket("ws://127.0.0.1:8000/ws");

ws.onopen = function () {
    ws.send("Client CONNECTED");
};

ws.onmessage = function (evt) {
    document.getElementById("p1").innerHTML = evt.data;
};

ws.onclose = function () {
    console.log("Client DISCONNECTED");
};

websocket-client 库(或者至少是您正在使用的 run_forever 方法)是同步的,不能与 asyncio 结合使用,除非 运行 它在自己的线程中。

相反,您需要一个异步 websocket 客户端实现,例如 Tornado's websocket_connect (or aiohttp's ws_connect)