【问题标题】:How do I send a websocket message in Tornado at will?如何在 Tornado 中随意发送 websocket 消息?
【发布时间】:2018-01-29 17:04:52
【问题描述】:

我是 Tornado 的新手,想知道是否可以从我的 Python 程序中随意向所有客户端发送消息 (write_message)?例如,假设我的程序正在监视一个目录以查看文件是否出现/存在。当它出现时,我想向浏览器客户端发送该文件存在的 Web 套接字消息。我似乎无法理解如何在不首先收到 websocket 消息(on_message 处理程序)的情况下调用“write_message”方法。

即使我使用“PeriodicCallback”方法,我仍然不清楚我实际上是如何调用“write_message”方法的。有没有关于如何调用“write_message”而不在“on_message”处理程序中执行的示例?

【问题讨论】:

    标签: python websocket tornado


    【解决方案1】:

    您需要保留一个打开的 websocket 集合并随意遍历该集合以发送消息。

    例如,我会在客户端连接到your.domain.example/test/ 的任何时候发送一条消息,但只要你想发送一些东西,这个想法都是一样的:

    import os.path
    import logging
    
    from tornado import ioloop, web, websocket
    
    
    SERVER_FOLDER = os.path.abspath(os.path.dirname(__file__))
    LOGGER = logging.getLogger('tornado.application')
    
    
    class TestHandler(web.RequestHandler):
        def get(self):
            server = ioloop.IOLoop.current()
            data = "whatever"
            server.add_callback(DefaultWebSocket.send_message, data)
            self.set_status(200)
            self.finish()
    
    
    class DefaultWebSocket(websocket.WebSocketHandler):
        live_web_sockets = set()
    
        def open(self):
            LOGGER.debug("WebSocket opened")
            self.set_nodelay(True)
            self.live_web_sockets.add(self)
            self.write_message("you've been connected. Congratz.")
    
        def on_message(self, message):
            LOGGER.debug('Message incomming: %s', message)
    
        def on_close(self):
            LOGGER.debug("WebSocket closed")
    
        @classmethod
        def send_message(cls, message):
            removable = set()
            for ws in cls.live_web_sockets:
                if not ws.ws_connection or not ws.ws_connection.stream.socket:
                    removable.add(ws)
                else:
                    ws.write_message(message)
            for ws in removable:
                cls.live_web_sockets.remove(ws)
    
    
    def serve_forever(port=80, address=''):
        application = web.Application([
                (r"/test/", TestHandler),
                (r"/websocket/", DefaultWebSocket),
                ...
            ],
            static_path=os.path.join(SERVER_FOLDER, ...),
            debug=True,
        )
        application.listen(port, address)
        LOGGER.debug(
                'Server listening at http://%s:%d/',
                address or 'localhost', port)
        ioloop.IOLoop.current().start()
    
    
    if __name__ == "__main__":
        serve_forever()
    

    您显然需要使用以下 JavaScript 在浏览器中创建一个 websocket:

    socket = new WebSocket('ws://your.domain.example:80/websocket/');
    

    并进行相应的管理。

    【讨论】:

    • Eww。您必须将self 保存到全局变量中。我想知道是否有更好的方法来解决这个问题。
    • @CollinBell 您始终可以为set 使用类变量并将发送函数转换为@classmethod ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    相关资源
    最近更新 更多