如何让 Tornado websocket 客户端接收服务器通知?

Posted

技术标签:

【中文标题】如何让 Tornado websocket 客户端接收服务器通知?【英文标题】:How to make a Tornado websocket client recieve server notifications? 【发布时间】:2016-12-04 13:24:50 【问题描述】:

我正在尝试制作一个通常向服务器发送请求并接收响应的应用程序。如果只是这样,我会选择 HTTP 并称之为交易。但是对服务器的一些请求对其他客户端进行了更改,因此我希望服务器向所有受影响的客户端发送一条消息,让他们应该更新。 为此,我选择了 WebSockets 协议和 Tornado 库来使用 Python 来处理它。尽管存在异步,但简单的消息交换非常简单。但是,WebSocket 客户端确实不是那么可配置的,我一直在努力让客户端监听传入的通知,而不会中断主消息交换。

服务器部分由tornado.websocket.WebSocketHandler 表示,它有一个on_message 方法:

from tornado.websocket import WebSocketHandler

class MyHandler(WebSocketHandler):
    def on_message(self, message):
        print('message:', message)

我想在客户端部分使用类似的东西,它仅由函数tornado.websocket.websocket_connect (source) 表示。这个函数初始化了一个tornado.websocket.WebSocketClientConnection(source)对象,里面有一个on_message方法,但是由于纠缠的异步结构,我一直没能正确覆盖它,不破坏主消息交换。

我尝试使用的另一种方法是on_message_callback。这听起来像是我可以使用的东西,但我不知道如何将它与read_message 一起使用。这是我最好的尝试:

import tornado.websocket
import tornado.ioloop

ioloop = tornado.ioloop.IOLoop.current()

def clbk(message):
    print('received', message)

async def main():
    url = 'server_url_here'
    conn = await tornado.websocket.websocket_connect(url, io_loop = ioloop, on_message_callback=clbk)
    while True:
        print(await conn.read_message())  # The execution hangs here
        st = input()
        conn.write_message(st)

ioloop.run_sync(main)

这是服务器代码:

import tornado.ioloop
import tornado.web
import tornado.websocket
import os


class EchoWebSocket(tornado.websocket.WebSocketHandler):
    def open(self):
        self.write_message('hello')

    def on_message(self, message):
        self.write_message(message)
        self.write_message('notification')

if __name__ == "__main__":
    app = tornado.web.Application([(r"/", EchoWebSocket)])
    app.listen(os.getenv('PORT', 8080))
    tornado.ioloop.IOLoop.current().start()

我不知道这里发生了什么。我是否朝着正确的方向前进?

【问题讨论】:

【参考方案1】:

这里有两个问题:

    使用on_message_callback 或循环await read_message(),但不能同时使用。如果您提供回调,则消息将仅传递给该回调,并且不会保存以供 read_message 使用。 input 正在阻塞并且不能很好地与 Tornado 配合使用。在这个小玩具演示中很好,但如果你想在生产中做这样的事情,你可能想做一些事情,比如在sys.stdin 周围包裹一个Pipeiostream 并使用stream.read_until('\n')

【讨论】:

但是主要问题呢?如何在运行常规消息交换的同时接收通知? 通过回调,您可以摆脱while/read_message 循环并在需要时调用conn.write_message。使用input() 进行这项工作很棘手,但如果您真正想要调用write_message 的时间在回调中,它会起作用。对于协程,使用IOLoop.spawn_callback 启动两个协程,一个运行读取循环,一个执行您想要执行的任何其他操作来生成消息。

以上是关于如何让 Tornado websocket 客户端接收服务器通知?的主要内容,如果未能解决你的问题,请参考以下文章

Tornado websocket 客户端:如何异步 on_message? (从未等待协程)

使用 tornado websockets 传递消息

Tornado-长轮询_webSocket

如何在 Tornado 中通过 websocket 传输 .png 或 .jpg 文件

如何使用 Tornado 监听来自多个地方的传入 websocket 消息?

让 Tornado Websocket 运行 render()