[英]How to asynchronously send data with socketio to a web client?
The following situation: 以下情况:
socketio
to listen for incoming messages (= JavaScript). socketio
侦听传入的消息(= JavaScript)。 flask-socketio
with eventlet
to send data (= Python). flask-socketio
和eventlet
发送数据(= Python)。 Everything works if the client sends a message to the server. 如果客户端向服务器发送消息,则一切正常。 The server receives the messages.
服务器接收消息。 Example:
例:
socketio = SocketIO(app, engineio_logger=True, async_mode="eventlet")
@socketio.on("mymsg")
def handle_event(message):
print("received message: " + str(message))
Unfortunately the other way around does not work - to some extent. 不幸的是,反过来也行不通 - 在某种程度上。 I have a thread producing live data about 5 to 10 times a second the web frontend should display.
我有一个线程产生实时数据,每秒约5到10次Web前端应该显示。 It should be sent to the client.
它应该发送给客户端。
First: It does not work at all if the thread producing the data tries to invoke sockeito.emit()
directly. 第一:如果生成数据的线程试图直接调用
sockeito.emit()
它根本不起作用。 The reason for that is unclear to me but somehow plausible as flask-socketio
with eventlet
follows different async models, as the documentation says. 其中的原因尚不清楚,但有些方面似乎有道理,因为带有
eventlet
flask-socketio
eventlet
遵循不同的异步模型,正如文档所述。
Second: Decoupling classic threads from the async model of flask/eventlet works to some extent. 第二:将经典线程与flask / eventlet的异步模型分离在一定程度上起作用。 I attempt to use an
eventlet
queue for that. 我尝试使用
eventlet
队列。 All status data my thread produces is put into the queue like this: 我的线程产生的所有状态数据都放入队列中,如下所示:
statusQueue.put(statusMsg)
This works fine. 这很好用。 Debugging messages show that this is performed all the time, adding data after data to the queue.
调试消息显示此操作始终执行,将数据添加到队列之后。
As the documentation of flasks tells I'm adviced to use socketio.start_background_task()
in order to get a running "thread" in a compatible mode to the async model socketio
uses. 正如烧瓶的文档告诉我,我建议使用
socketio.start_background_task()
以便在兼容模式下获得正在运行的“线程” socketio
async async model。 So I am using this code: 所以我使用这段代码:
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)
The strange thing where I'm asking you for help is this: The first call to statusQueue.get()
blocks as expected as initially the queue is empty. 我要求你帮忙的奇怪之处是:第一次调用
statusQueue.get()
阻塞,因为最初队列是空的。 The first message is taken from the queue and sent via socketio
. 第一条消息从队列中获取并通过
socketio
发送。 Debug messages at the client show that the web client receives this message. 客户端上的调试消息显示Web客户端收到此消息。 Debug messages at the server show that the message is sent successfully.
服务器上的调试消息显示消息已成功发送。 But: As soon as the next
statusQueue.get()
is invoked, the call blocks indefinitely, regardless of how many messages get put into the queue. 但是:只要调用下一个
statusQueue.get()
,调用就会无限期地阻塞,无论有多少消息被放入队列。
I'm not sure if this helps but some additional information: The socketio
communication is perfectly intact. 我不确定这是否有帮助,但是还有一些额外的信息:
socketio
通信完好无损。 If the client sends data, everything works. 如果客户端发送数据,一切正常。 Additionally I can see the ping-pongs both client and server play to keep the connections alive.
此外,我可以看到客户端和服务器的ping-pongs一直保持连接活动。
My question is: How can I properly implement a server that is capable of sending messages to the client asynchronously? 我的问题是:如何正确实现能够异步向客户端发送消息的服务器?
Have a look at https://github.com/jkpubsrc/experiment-python-flask-socketio for a minimalistic code example featuring the Python-Flask server process and a JQuery based JavaScript client. 有关Python-Flask服务器进程和基于JQuery的JavaScript客户端的简约代码示例, 请查看https://github.com/jkpubsrc/experiment-python-flask-socketio 。
(FYI: As these are status messages not necessarily every message needs to arrive. But I very much would like to receive at least some messages not only the very first message and then no other message.) (仅供参考:由于这些是状态消息,因此不一定每条消息都需要到达。但我非常希望至少收到一些消息,不仅是第一条消息,还有其他消息。)
Thank you for your responses. 谢谢你的回复。
I left two solutions to make the code work as pull requests. 我留下了两个解决方案,使代码可以作为拉取请求。
Basically, the answer is: you choose one technology and stick a process with it: 基本上,答案是:您选择一种技术并坚持使用它:
async_mode=threading
? async_mode=threading
? Great, use stdlib Queue. async_mode=eventlet
? async_mode=eventlet
? Also great, use eventlet Queue and don't forget that stdlib time.sleep
or socket
IO will block everything else, fix with eventlet.monkey_patch()
time.sleep
或socket
IO会阻止其他的一切,与固定eventlet.monkey_patch()
With good knowledge of both eventlet and native threads you can carefully mix them into working code. 熟悉eventlet和本机线程,您可以仔细地将它们混合到工作代码中。 As of 2018-09, mixing doesn't work in friendly obvious way, as you already found.
正如您已经发现的那样,截至2018-09,混合不能以友好明显的方式起作用。 Sorry.
抱歉。 Patches are welcome.
欢迎补丁。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.