Сервер websocket Tornado и клиент websocket одновременно в одном l oop с AsyncIO - PullRequest
0 голосов
/ 27 мая 2020

Я хочу запустить сервер веб-сокетов торнадо вместе с отдельным клиентом веб-сокета одновременно на том же l oop, чтобы я мог получать данные от этого единственного клиента веб-сокета и отправлять их с сервера торнадо всем подключенным клиентам.

Я могу запустить сервер торнадо и клиент websocket, но сервер торнадо не отвечает на запрос клиента. Я получаю что-то вроде "ожидание ответа от 127.0.0.1:8000" .

Я думаю, у меня проблемы с асинхронностью. Я предполагаю, что мой клиент websocket блокирует весь процесс ...

У кого-нибудь есть идея?

Спасибо!

Сервер Tornado:

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");
};

1 Ответ

0 голосов
/ 28 мая 2020

Библиотека websocket-client (или, по крайней мере, метод run_forever, который вы используете) является синхронным и не может быть объединен с asyncio, кроме как путем его запуска в собственном потоке.

Вместо этого вам нужна реализация асинхронного клиента websocket, например Tornado websocket_connect (или aiohttp ws_connect)

...