我想在dictionary中存储和管理用户websocket连接,这样我就可以 for each 用户创建自定义事件.

Here's a really simple implementation of what I'm trying to achieve:

from fastapi import FastAPI, WebSocket
app = FastAPI()
con = {}
@app.websocket("/ws/{id}")
async def websocket_endpoint(websocket: WebSocket, id: str):
    try:
        print("connect", id)
        await websocket.accept()
        con[id] = websocket
        print("check", con.keys())
        for uid in con:
            print(uid)
            await con[uid].send_text("hello")
    except Exception as e:
        print(e)

and here's the log :

INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [26605] using StatReload
INFO:     Started server process [26610]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
connect 1
INFO:     ('127.0.0.1', 48346) - "WebSocket /ws/1" [accepted]
check dict_keys(['1'])
1
INFO:     connection open
connect 2
INFO:     ('127.0.0.1', 48354) - "WebSocket /ws/2" [accepted]
check dict_keys(['1', '2'])
1
Unexpected ASGI message 'websocket.send', after sending 'websocket.close'.
INFO:     connection open

当我使用客户端1连接到WebSocket时,一切都按预期进行,我收到消息hello.

client 1 log:

CONNECTING: WS://LOCALHOST:8000/WS/1

CONNECTION READY

hello

CONNECTION CLOSED!

但是,当秒客户端连接到websocket时,它会在服务器中返回一个异常:

Unexpected ASGI message 'websocket.send', after sending 'websocket.close'.

and client 2 doesn't get any message:

CONNECTING: WS://LOCALHOST:8000/WS/1

CONNECTION READY

CONNECTION CLOSED!

I run the app like this:

uvicorn main:app --reload

我到底做错了什么?

推荐答案

Your FastAPI WebSocket route does not seem to have an event loop to continuously handle incoming or outgoing messages for each connected client.
Meaning: as soon as the function websocket_endpoint finishes executing, the WebSocket connection is automatically closed by FastAPI, leading to the unexpected ASGI message error.

connections字典outside放在函数范围内将允许跨不同的函数调用存储和访问多个WebSocket连接.

您需要一个while True:循环来确保WebSocket连接保持打开,从而允许连续发送和接收消息.

添加一些错误处理并不是一个坏主意:这将有助于通过WebSocketDisconnect优雅地处理客户端断开连接.这样,当客户端断开连接时,可以从connections字典中删除该连接.

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from typing import Dict

app = FastAPI()
connections: Dict[str, WebSocket] = {}

@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: str):
    await websocket.accept()
    connections[client_id] = websocket

    try:
        while True:
            data = await websocket.receive_text()
            # Do something with received data (optional)
            
            for uid, ws in connections.items():
                await ws.send_text(f"Client {client_id} says: {data}")

    except WebSocketDisconnect:
        del connections[client_id]

例如,该代码将来自任何客户端的传入消息发送到所有连接的客户端.您可以根据您的用例需要对其进行定制.

新工作流程:

   +---------------------+
   |  websocket_endpoint |
   +-------+-------------+
           |
           |
   +-------v-----------------+
   |await websocket.accept() |
   +-------+-----------------+
           |
           |
   +-------v----------------------------+
   | connections[client_id] = websocket |
   +-------+----------------------------+
           |
           |
           |<-------------------------------------------+
           |                                            |
   +-------v----------+                        +--------+------------+
   |   while True:    |                        | WebSocketDisconnect |
   +-------+----------+                        +--------+------------+
           |                                            |
           |                                            |
   +-------v-------------------------------+   +--------v-------------------+
   | data = await websocket.receive_text() |<--| del connections[client_id] |
   +-------+-------------------------------+   +----------------------------+
           |
           |
   +-------v-----------------------------+
   | for uid, ws in connections.items(): |
   +-------+-----------------------------+
           |
           |
   +-------v--------------+          +--------------------+
   | await ws.send_text() |---...--->|     while True:    |
   +-------+--------------+          +--------------------+

Python相关问答推荐

给定数据点,制定它们的关系

在使用Guouti包的Python中运行MPP模型时内存不足

如何计算两极打印机中 * 所有列 * 的出现次数?

将输入管道传输到正在运行的Python脚本中

Python键入协议默认值

DataFrames与NaN的条件乘法

如何根据一列的值有条件地 Select 前N组?

改进大型数据集的框架性能

在Python 3中,如何让客户端打开一个套接字到服务器,发送一行JSON编码的数据,读回一行JSON编码的数据,然后继续?

将scipy. sparse矩阵直接保存为常规txt文件

如何使regex代码只适用于空的目标单元格

python panda ExcelWriter切换动态公式到数组公式

matplotlib图中的复杂箭头形状

巨 Python :逆向猜谜游戏

如何求相邻对序列中元素 Select 的最小代价

为什么t sns.barplot图例不显示所有值?'

mdates定位器在图表中显示不存在的时间间隔

在Django中重命名我的表后,旧表中的项目不会被移动或删除

504未连接IB API TWS错误—即使API连接显示已接受''

Polars定制函数返回多列