以下情况:
- Web 客户端:使用 JavaScript
socketio
收听传入的消息(= JavaScript)。 - 网络服务器:使用
flask-socketio
与eventlet
发送数据(= Python)。
如果客户端向服务器发送消息,一切正常。服务器接收消息。示例:
socketio = SocketIO(app, engineio_logger=True, async_mode="eventlet")
@socketio.on("mymsg")
def handle_event(message):
print("received message: " + str(message))
不幸的是,在某种程度上,反过来行不通。我有一个线程以每秒 5 到 10 次的速度生成 Web 前端应显示的实时数据。它应该发送给客户。
首先:如果生成数据的线程试图调用 sockeito.emit()
,它根本不起作用。直接地。其原因我不清楚,但在某种程度上是合理的 flask-socketio
与 eventlet
如文档所述,遵循不同的异步模型。
其次:将经典线程与flask/eventlet的异步模型解耦在一定程度上起到了作用。我尝试使用 eventlet
排队等候。我的线程产生的所有状态数据都像这样放入队列中:
statusQueue.put(statusMsg)
这很好用。调试消息显示,这一直在执行,将数据一个接一个地添加到队列中。
正如 flasks 的文档所说,我被建议使用 socketio.start_background_task()
为了在与异步模型兼容的模式下运行“线程”socketio
使用。所以我正在使用这段代码:
def emitStatus():
print("Beginning to emit ...")
while True:
msg = statusQueue.get()
print("Sending status packet: " + str(msg))
socketio.emit("status", msg, broadcast=True)
statusQueue.task_done()
print("Sending status packet done.")
print("Terminated.")
socketio.start_background_task(emitStatus)
我向您寻求帮助的奇怪之处在于:第一次调用 statusQueue.get()
如预期的那样阻塞,因为最初队列是空的。第一条消息从队列中取出并通过 socketio
发送.客户端的调试消息显示 Web 客户端收到此消息。服务器端的调试消息显示消息发送成功。但是:尽快下一个statusQueue.get()
被调用时,无论有多少消息放入队列,调用都会无限期地阻塞。
我不确定这是否有帮助,但一些额外的信息:socketio
通讯完好无损。如果客户端发送数据,一切正常。此外,我可以看到客户端和服务器都在播放乒乓球来保持连接。
我的问题是:如何正确实现能够向客户端异步发送消息的服务器?
看看https://github.com/jkpubsrc/experiment-python-flask-socketio以 Python-Flask 服务器进程和基于 JQuery 的 JavaScript 客户端为特色的简约代码示例。
(仅供引用:由于这些是状态消息,不一定每条消息都需要到达。但我非常希望至少收到一些消息,而不仅仅是第一条消息,然后没有其他消息。)
感谢您的回复。
最佳答案
我留下了两个解决方案来使代码作为拉取请求工作。
基本上,答案是:您选择一种技术并坚持采用它的流程:
- 参加
async_mode=threading
?太好了,使用 stdlib 队列。除非必须,否则不要导入 eventlet。 - 参加
async_mode=eventlet
?也很棒,使用 eventlet Queue 并且不要忘记 stdlibtime.sleep
或socket
IO 将阻止其他一切,用eventlet.monkey_patch()
修复 - 如果您必须同时使用 eventlet 和线程,最好的方法是让它们存在于单独的操作系统进程中并通过本地套接字进行通信。这是额外的工作,但它非常坚固,您知道它是如何工作的以及为什么它不会损坏。
在充分了解 eventlet 和 native 线程的情况下,您可以小心地将它们混合到工作代码中。正如您已经发现的那样,截至 2018-09 年,混音并没有以友好明显的方式进行。对不起。欢迎补丁。
关于python-3.x - 如何使用 socketio 将数据异步发送到 Web 客户端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52025853/