如何使用socketio异步将数据发送到Web客户端?

时间:2018-08-26 11:37:02

标签: python-3.x socket.io message-queue eventlet

以下情况:

  • Web客户端:使用JavaScript socketio侦听传入消息(= JavaScript)。
  • Web服务器:使用flask-socketioeventlet发送数据(= Python)。

如果客户端向服务器发送消息,则一切正常。服务器收到消息。示例:

socketio = SocketIO(app, engineio_logger=True, async_mode="eventlet")

@socketio.on("mymsg")
def handle_event(message):
    print("received message: " + str(message))

不幸的是,在某种程度上,另一种方法不起作用。我有一个线程会在Web前端每秒显示大约5到10次的实时数据。它应该发送给客户端。

第一:如果产生数据的线程试图直接调用sockeito.emit(),则根本不起作用。对于我来说,其原因尚不清楚,但可以理解为flask-socketioeventlet遵循不同的异步模型,如文档所述。

第二个:将经典线程从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客户端的简约代码示例。

(仅供参考:由于这些是状态消息,不一定每条消息都需要到达。但是我非常希望至少收到一些消息,不仅是第一条消息,然后是其他消息。)

感谢您的回复。

1 个答案:

答案 0 :(得分:0)

我留下了两种解决方案,以使代码可以作为请求请求使用。

基本上,答案是:您选择一种技术并坚持使用它:

  • 要去async_mode=threading吗?很好,请使用stdlib Queue。除非必须,否则不要导入eventlet。
  • 要去async_mode=eventlet吗?也很棒,请使用eventlet Queue,不要忘记stdlib time.sleepsocket IO会阻止其他所有内容,并使用eventlet.monkey_patch()
  • 进行修复。
  • 如果必须同时使用eventlet和线程,则最好的方法是让它们生活在单独的OS进程中并通过本地套接字进行通信。这是额外的工作,但是它非常健壮,您知道它是如何工作的以及为什么它不会破裂。

凭借对eventlet和本机线程的充分了解,您可以将它们仔细地混合到工作代码中。就像您已经发现的那样,截至2018-09年,混音无法以友好的明显方式进行。抱歉。欢迎打补丁。