WebSocket 双向通信完整教程 什么是 WebSocket传统 HTTP 的局限HTTP 协议是单向的客户端发起请求 → 服务端响应 → 连接关闭问题❌ 服务端不能主动推送消息❌ 需要轮询客户端不停问有新消息吗❌ 每次请求都要重新建立连接开销大WebSocket 的优势WebSocket 是全双工通信协议客户端 ←→ 服务端连接保持双方随时收发优势✅ 服务端可以主动推送消息✅ 连接持久化不需要反复建立连接✅ 实时性高延迟低✅ 带宽占用少典型应用场景场景说明即时聊天微信、Slack 等实时数据股票行情、体育比分在线游戏多人实时同步协作编辑Google Docs、腾讯文档通知推送系统通知、消息提醒回到顶部示例 1基础通信 - 客户端请求服务端响应场景描述客户端主动发送消息服务端接收后原样返回Echo 模式。代码结构d2/ ├── simple_server.py # 服务端 ├── simple_client.py # 客户端 └── requirements.txt # 依赖安装依赖pip install websockets12.0服务端代码 (simple_server.py) 最简单的 WebSocket 服务端 功能接收客户端消息原样返回 import asyncio import websockets # 处理每个客户端连接的函数 async def handle_client(websocket): print(有客户端连接了) # 持续监听客户端发来的消息 async for message in websocket: print(f收到消息: {message}) # 把消息原样发回去 await websocket.send(f服务端收到: {message}) # 主函数 async def main(): # 在本地 8765 端口启动服务 print(WebSocket 服务端启动在 ws://localhost:8765) async with websockets.serve(handle_client, localhost, 8765): await asyncio.Future() # 让服务一直运行 if __name__ __main__: asyncio.run(main())代码解析代码说明async def handle_client(websocket)定义处理函数每个客户端连接时调用async for message in websocket循环监听消息客户端断开时自动结束await websocket.send()发送消息给客户端websockets.serve()启动服务端监听指定地址和端口await asyncio.Future()保持服务运行不退出客户端代码 (simple_client.py) 最简单的 WebSocket 客户端 功能连接服务端发送消息接收回复 import asyncio import websockets async def main(): # 连接到服务端 uri ws://localhost:8765 print(f正在连接 {uri}...) async with websockets.connect(uri) as websocket: print(连接成功) # 发送 3 条消息测试 for i in range(1, 4): message f这是第 {i} 条消息 print(f发送: {message}) await websocket.send(message) # 等待服务端回复 response await websocket.recv() print(f收到回复: {response}) await asyncio.sleep(1) # 等待 1 秒再发下一条 print(测试完成) if __name__ __main__: asyncio.run(main())代码解析代码说明websockets.connect(uri)连接到服务端await websocket.send()发送消息给服务端await websocket.recv()等待接收服务端消息阻塞async with自动管理连接退出时自动关闭运行步骤终端 1 - 启动服务端cd d2 python simple_server.py终端 2 - 运行客户端cd d2 python simple_client.py运行结果服务端输出WebSocket 服务端启动在 ws://localhost:8765 有客户端连接了 收到消息: 这是第 1 条消息 收到消息: 这是第 2 条消息 收到消息: 这是第 3 条消息客户端输出正在连接 ws://localhost:8765... 连接成功 发送: 这是第 1 条消息 收到回复: 服务端收到: 这是第 1 条消息 发送: 这是第 2 条消息 收到回复: 服务端收到: 这是第 2 条消息 发送: 这是第 3 条消息 收到回复: 服务端收到: 这是第 3 条消息 测试完成时序图客户端 服务端 | | |--- connect ------------------| 建立连接 | | |--- 这是第 1 条消息 ---------| |-- 服务端收到: ... ---------| | | |--- 这是第 2 条消息 ---------| |-- 服务端收到: ... ---------| | | |--- 这是第 3 条消息 ---------| |-- 服务端收到: ... ---------| | | |--- close --------------------| 关闭连接关键点必须先启动服务端客户端才能连接一问一答模式客户端发送 → 等待回复 → 再发送这是最基础的 WebSocket 通信模式回到顶部示例 2服务端主动推送场景描述服务端可以不等客户端请求主动推送消息。同时客户端也可以发送消息实现真正的全双工通信。代码结构d2/ ├── push_server.py # 服务端主动推送 └── push_client.py # 客户端同时收发服务端代码 (push_server.py) 服务端主动推送消息示例 功能 1. 客户端连接后服务端主动发送欢迎消息 2. 每隔 3 秒服务端主动推送一条消息 3. 同时还能接收并回复客户端的消息 import asyncio import websockets from datetime import datetime async def handle_client(websocket): 处理每个客户端 print(f[{datetime.now():%H:%M:%S}] 客户端已连接) # 1. 服务端主动发送欢迎消息 welcome 欢迎连接我是服务端我会每 3 秒给你推送消息 await websocket.send(welcome) print(f[{datetime.now():%H:%M:%S}] 已发送欢迎消息) try: # 同时运行两个任务定时推送 接收消息 await asyncio.gather( push_periodic_messages(websocket), receive_client_messages(websocket) ) except Exception as e: print(f[{datetime.now():%H:%M:%S}] 客户端断开连接) async def push_periodic_messages(websocket): 定时推送消息给客户端 count 1 while True: await asyncio.sleep(3) # 每 3 秒 # 服务端主动推送不需要客户端先发消息 message f [服务端推送 #{count}] 现在时间是 {datetime.now():%H:%M:%S} await websocket.send(message) print(f[{datetime.now():%H:%M:%S}] 推送消息给客户端) count 1 async def receive_client_messages(websocket): 接收客户端消息 async for message in websocket: print(f[{datetime.now():%H:%M:%S}] 收到客户端消息: {message}) # 回复客户端 reply f✅ 服务端收到: {message} await websocket.send(reply) async def main(): host localhost port 8765 print(fWebSocket 服务端启动在 ws://{host}:{port}) print(等待客户端连接...) async with websockets.serve(handle_client, host, port): await asyncio.Future() if __name__ __main__: asyncio.run(main())核心亮点# 关键代码服务端主动推送 async def push_periodic_messages(websocket): while True: await asyncio.sleep(3) await websocket.send(推送内容) # 主动发送不等客户端请求客户端代码 (push_client.py) 接收服务端推送消息的客户端 功能 1. 连接后持续监听服务端的推送 2. 同时可以向服务端发送消息 import asyncio import websockets async def receive_messages(websocket): 持续接收服务端的消息 print(\n 接收服务端消息 ) try: async for message in websocket: # 服务端推送的消息会在这里收到 print(f\n 收到: {message}) print( , end, flushTrue) except: print(\n连接已断开) async def send_messages(websocket): 发送消息给服务端 print(\n 你可以输入消息 ) print(输入任意文字发送给服务端输入 quit 退出\n) loop asyncio.get_event_loop() while True: print( , end, flushTrue) user_input await loop.run_in_executor(None, input) if user_input.strip().lower() quit: print(正在断开连接...) break if user_input.strip(): await websocket.send(user_input.strip()) async def main(): uri ws://localhost:8765 print(f正在连接 {uri}...) try: async with websockets.connect(uri) as websocket: print(✅ 连接成功) # 关键同时运行接收和发送两个任务 receive_task asyncio.create_task(receive_messages(websocket)) send_task asyncio.create_task(send_messages(websocket)) # 等待任意一个任务结束 done, pending await asyncio.wait( [receive_task, send_task], return_whenasyncio.FIRST_COMPLETED ) # 取消未完成的任务 for task in pending: task.cancel() except ConnectionRefusedError: print(❌ 连接失败请确保服务端已启动。) except Exception as e: print(f❌ 错误: {e}) print(已断开连接。) if __name__ __main__: asyncio.run(main())核心亮点# 关键代码同时收发全双工 await asyncio.gather( receive_messages(websocket), # 后台持续接收推送 send_messages(websocket) # 前台等待用户输入 )运行步骤终端 1 - 启动服务端cd d2 python push_server.py终端 2 - 运行客户端cd d2 python push_client.py运行结果客户端输出正在连接 ws://localhost:8765... ✅ 连接成功 接收服务端消息 你可以输入消息 输入任意文字发送给服务端输入 quit 退出 收到: 欢迎连接我是服务端我会每 3 秒给你推送消息 收到: [服务端推送 #1] 现在时间是 14:23:05 hello 收到: ✅ 服务端收到: hello 收到: [服务端推送 #2] 现在时间是 14:23:08 你好 收到: ✅ 服务端收到: 你好 收到: [服务端推送 #3] 现在时间是 14:23:11 quit 正在断开连接... 已断开连接。服务端输出WebSocket 服务端启动在 ws://localhost:8765 等待客户端连接... [14:23:02] 客户端已连接 [14:23:02] 已发送欢迎消息 [14:23:05] 推送消息给客户端 [14:23:06] 收到客户端消息: hello [14:23:08] 推送消息给客户端 [14:23:09] 收到客户端消息: 你好 [14:23:11] 推送消息给客户端 [14:23:12] 客户端断开连接时序图时间 客户端 服务端 -----|--------------------------------|-------------------------------- 0s |--- connect -------------------| 建立连接 |-- 欢迎消息 -------------------|主动推送 3s |-- 推送 #1 --------------------|主动推送不需要请求 5s |--- hello -------------------| |-- 服务端收到: hello --------| 6s |-- 推送 #2 --------------------|主动推送 8s |--- 你好 --------------------| |-- 服务端收到: 你好 ---------| 9s |-- 推送 #3 --------------------|主动推送 12s |--- quit -----------------------| 关闭连接关键点服务端主动推送每 3 秒自动发送不需要客户端请求全双工通信推送和对话同时进行互不干扰异步并发客户端同时运行两个任务接收 发送