You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python实现WebSocket消息广播?

如何用Python的WebSocket实现聊天室消息广播?

当然可行,核心问题是你的服务器没有维护客户端连接列表,也没有将收到的消息转发给其他客户端;同时客户端的连接逻辑也有问题,每次发消息都新建连接,无法持续接收广播。下面是修复后的完整实现:

服务端实现(带广播功能)

import asyncio
import websockets

# 维护所有活跃的WebSocket连接
connected_clients = set()

async def handle_client(websocket):
    # 客户端连接成功后加入集合
    connected_clients.add(websocket)
    try:
        async for message in websocket:
            print(f"收到消息: {message}")
            # 广播消息给所有其他客户端
            for client in connected_clients:
                if client != websocket:  # 跳过发消息的客户端,避免自己收到自己的消息
                    await client.send(message)
    finally:
        # 客户端断开连接后从集合移除
        connected_clients.remove(websocket)

async def main():
    async with websockets.serve(handle_client, "localhost", 8765):
        await asyncio.Future()  # 保持服务器运行

asyncio.run(main())

服务端关键改动说明:

  • 新增connected_clients集合,用于跟踪所有当前在线的客户端连接
  • handle_client函数在客户端连接时将其加入集合,断开时移除
  • 收到消息后遍历集合,将消息转发给所有其他客户端,可选跳过发送者本身

客户端实现(持久连接+异步收发)

import asyncio
import sys
from colorama import Fore

def delete_last_line():
    "删除STDOUT的最后一行"
    sys.stdout.write('\x1b[1A')
    sys.stdout.write('\x1b[2K')

async def receive_messages(websocket):
    "持续接收服务器广播的消息并打印"
    async for message in websocket:
        # 先清除当前输入行,避免消息和输入重叠
        delete_last_line()
        print(message)
        # 重新显示输入提示符
        sys.stdout.write("> ")
        sys.stdout.flush()

async def send_messages(websocket, username):
    "读取用户输入并发送到服务器"
    while True:
        message_input = input("> ")
        delete_last_line()
        message = f'{username}: {message_input}'
        await websocket.send(message)

async def main():
    username = input('Username: ')
    delete_last_line()
    if username == 'Default Box':
        username = f'{Fore.BLUE}☆ Default Box{Fore.WHITE}'
    print(f'设置用户名为 {username}')
    print('正在连接聊天室...')

    # 建立持久WebSocket连接
    async with websockets.connect("ws://localhost:8765") as websocket:
        # 发送加入消息
        join_message = f'{username} {Fore.YELLOW}已加入聊天室{Fore.WHITE}'
        await websocket.send(join_message)
        
        # 同时运行接收和发送任务
        receive_task = asyncio.create_task(receive_messages(websocket))
        send_task = asyncio.create_task(send_messages(websocket, username))
        
        # 等待任务完成(实际会一直运行直到断开)
        await asyncio.gather(receive_task, send_task)

if __name__ == "__main__":
    asyncio.run(main())

客户端关键改动说明:

  • 改为持久连接,不再每次发消息新建连接,保证能持续接收服务器的广播
  • 拆分出receive_messages和send_messages两个异步任务,同时处理消息接收和用户输入
  • 修复了原代码中收到消息后又发回服务器的错误逻辑
  • 优化了控制台输出,避免消息和输入行重叠

测试方法

  1. 先启动服务端
  2. 打开多个终端窗口运行客户端,设置不同用户名
  3. 在任意客户端发送消息,其他客户端都会收到广播

内容的提问来源于stack exchange,提问作者Default Box

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 00:06:26