如何让 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 中通过 websocket 传输 .png 或 .jpg 文件