与 Quart 中的 websockets 双向通信

Bidirectional communiation with websockets in Quart

我希望能够在 Quart 中使用 WebSocket 来接收发送的任何消息,并发送我可能需要发送的任何消息。无法保证消息会在发送和接收之间交替。

例如,Quart's tutorial page on WebSockets 包含以下代码段:

@app.websocket('/api/v2/ws')
@collect_websocket
async def ws(queue):
    while True:
        data = await queue.get()
        await websocket.send(data)

不知何故,我想修改while True循环中的代码,以便我可以检查是否有任何数据要接收,但如果没有,我将改为检查队列。

我希望只有在有东西要接收时才能等待在套接字上接收(如果 receive 方法中有一个 timeout 参数,这也许可以实现),但这不是一个选择。

那么,我怎样才能 await 用于更新的 WebSocket 同时还 await 用于更新的其他东西

Quart 的作者在 post Websockets in Quart 中回答了这个问题,其中包含一个片段,我对其稍作修改以获得以下内容:

import asyncio

from quart import copy_current_websocket_context, Quart, websocket

app = Quart(__name__)

@app.websocket('/ws')
async def ws():

    async def consumer():
        while True:
            data = await websocket.receive()

    async def producer():
        while True:
            await asyncio.sleep(1)
            await websocket.send(b'Message')

    consumer_task = asyncio.ensure_future(consumer())
    producer_task = asyncio.ensure_future(producer())
    try:
        await asyncio.gather(consumer_task, producer_task)
    finally:
        consumer_task.cancel()
        producer_task.cancel()

该代码片段创建了两个不同的异步函数,它们各自具有 while True 循环。然后,Python 的 asyncio.ensure_future is used to create two different Task 继续工作。最后,调用 asyncio.gather 对任务进行并发评估。

通过在 ws 的定义中定义这两个任务,它们充当闭包,这意味着它们可以访问 websocket "special" 全局对象,该对象仅在ws 函数。如果你想在 ws 函数体之外定义这些函数,也许是因为你需要从其他地方调用它们,你可以在将它们传递给 ensure_future 时使用 Quart 中的 copy_current_websocket_context 函数:

consumer_task = asyncio.ensure_future(
    copy_current_websocket_context(consumer)()
)