Отправить данные из другого класса через ws после подключения клиента - PullRequest
0 голосов
/ 03 января 2019

Я хочу отправить данные через веб-сокеты, как только клиент подключится.Данные находятся в другом месте, чем обработчик Websocket.Как я могу получить данные для клиента?

Сервер должен содержать цикл и обработчик.В соединителе я подключаюсь к сокету tcp, чтобы получить данные из какого-то оборудования.Я ожидаю, что будет открыто не более 6 веб-сокетов за один раз.Данные поступают как поток из сокета TCP.

server.py

import os
from tornado import web, websocket
import asyncio
import connector


class StaticFileHandler(web.RequestHandler):

    def set_default_headers(self):
        self.set_header("Access-Control-Allow-Origin", "*")

    def get(self):
        self.render('index.html')


class WSHandler(websocket.WebSocketHandler):
    def open(self):
        print('new connection')
        self.write_message("connected")

    def on_message(self, message):
        print('message received %s' % message)
        self.write_message("pong")

    def on_close(self):
        print('connection closed')


public_root = 'web_src'

handlers = [
    (r'/', StaticFileHandler),
    (r'/ws', WSHandler),
]

settings = dict(
    template_path = os.path.join(os.path.dirname(__file__), public_root),
    static_path = os.path.join(os.path.dirname(__file__), public_root),
    debug = True
)

app = web.Application(handlers, **settings)

sensorIP = "xxx.xxx.xxx.xxx"

if __name__ == "__main__":
    app.listen(8888)
    asyncio.ensure_future(connector.main_task(sensorIP))
    asyncio.get_event_loop().run_forever()

connector.py

import yaml
import asyncio


class RAMReceiver:
    def __init__(self, reader):
        self.reader = reader
        self.remote_data = None
        self.initParams = None

    async def work(self):
        i = 0
        while True:
            data = await self.reader.readuntil(b"\0")
            self.remote_data = yaml.load(data[:-1].decode("utf-8", 
            "backslashreplace"))

            # here i want to emit some data
            # send self.remote_data to websockets 

            if i == 0:
                i += 1
                self.initParams = self.remote_data

                # here i want to emit some data after open event is 
                # triggered
                # send self.initParams as soon as a client has connected


async def main_task(host):
    tasks = []
    (ram_reader,) = await asyncio.gather(asyncio.open_connection(host, 
    51000))
    receiver = RAMReceiver(ram_reader[0])
    tasks.append(receiver.work())

while True:
    await asyncio.gather(*tasks)

1 Ответ

0 голосов
/ 03 января 2019

Вы можете использовать функцию Tornado add_callback для вызова метода вашего обработчика веб-сокетов для отправки сообщений.

Вот пример:

1. Создайте дополнительный метод в обработчике веб-сокета, который будет получать сообщение от connector.py и отправлять подключенным клиентам:

# server.py

class WSHandler(websocket.WebSocketHandler):

    # make it a classmethod so that 
    # it can be accessed directly
    # from class without `self`
    @classmethod 
    async def send_data(cls, data):
         # write your code for sending data to client

2. Передайте текущие IOLoop и WSHandler.send_data на ваш connector.py:

# server.py

from tornado import ioloop

...

if __name__ == "__main__":
    ...
    io_loop = ioloop.IOLoop.current() # current IOLoop
    callback = WSHandler.send_data
    # pass io_loop and callback to main_task
    asyncio.ensure_future(connector.main_task(sensorIP, io_loop, callback))
    ...

3. Затем измените функцию main_task в connector.py, чтобы получить io_loop и callback. Затем передайте io_loop и callback на RAMReceiver.

4. Наконец, используйте io_loop.add_callback для вызова WSHandler.send_data:

class RAMReceiver:
    def __init__(self, reader, io_loop, callback):
        ...
        self.io_loop = io_loop
        self.callback = callback

    async def work(self):
        ...
        data = "Some data"
        self.io_loop.add_callback(self.callback, data)
        ...
...