客户端连接后通过ws从其他类发送数据

时间:2019-01-03 10:00:23

标签: python-3.x websocket tornado python-asyncio

我想在客户端连接后立即通过websocket发送数据。 数据位于Websocket处理程序之后的另一个位置。如何将数据发送给客户端?

服务器应保留循环和处理程序。在连接器中,我连接到tcp套接字以从某些硬件中获取数据。我希望一次打开6个Websocket。数据作为流从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 :(得分:0)

您可以使用Tornado的add_callback函数在websocket处理程序上调用方法来发送消息。

这是一个例子:

1。。在您的websocket处理程序上创建其他方法,该方法将从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。。将当前正在运行的IOLoopWSHandler.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_loopcallback。然后将io_loopcallback传递到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)
        ...