当前位置: 首页 > news >正文

WebSocket 双向通信完整教程

什么是 WebSocket?

传统 HTTP 的局限

HTTP 协议是单向的:

客户端发起请求 → 服务端响应 → 连接关闭

问题:

  • ❌ 服务端不能主动推送消息
  • ❌ 需要轮询(客户端不停问"有新消息吗?")
  • ❌ 每次请求都要重新建立连接(开销大)

WebSocket 的优势

WebSocket 是全双工通信协议:

客户端 ←→ 服务端(连接保持,双方随时收发)

优势:

  • ✅ 服务端可以主动推送消息
  • ✅ 连接持久化(不需要反复建立连接)
  • ✅ 实时性高(延迟低)
  • ✅ 带宽占用少

典型应用场景

场景说明
即时聊天微信、Slack 等
实时数据股票行情、体育比分
在线游戏多人实时同步
协作编辑Google Docs、腾讯文档
通知推送系统通知、消息提醒

回到顶部

示例 1:基础通信 - 客户端请求,服务端响应

场景描述

客户端主动发送消息,服务端接收后原样返回(Echo 模式)。

代码结构

d2/ ├── simple_server.py # 服务端 ├── simple_client.py # 客户端 └── requirements.txt # 依赖

安装依赖

pip install websockets==12.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 -------------------->| 关闭连接

关键点

  1. 必须先启动服务端,客户端才能连接
  2. 一问一答模式:客户端发送 → 等待回复 → 再发送
  3. 这是最基础的 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(f"WebSocket 服务端启动在 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="", flush=True) except: print("\n连接已断开") async def send_messages(websocket): """发送消息给服务端""" print("\n========== 你可以输入消息 ==========") print("输入任意文字发送给服务端,输入 'quit' 退出\n") loop = asyncio.get_event_loop() while True: print(">>> ", end="", flush=True) 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_when=asyncio.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 ----------------------->| 关闭连接

关键点

  1. 服务端主动推送:每 3 秒自动发送,不需要客户端请求
  2. 全双工通信:推送和对话同时进行,互不干扰
  3. 异步并发:客户端同时运行两个任务(接收 + 发送)
http://www.jsqmd.com/news/1137116/

相关文章:

  • 城市交通管理终极指南:Traffic Manager: President Edition 完全解析
  • EventReduce未来展望:数据库查询优化的下一个里程碑
  • OpenTelemetry Go SDK配置热更新终极指南:零停机可观测性调优的5个高效策略
  • Miniworld模块化设计揭秘:如何扩展模拟器功能与自定义实体
  • 终极django-mongoengine用户指南:表单处理与视图开发实战
  • 13DOF传感器与PIC32MX675F256L在定位导航系统中的应用
  • Quantdom安全使用手册:量化交易回测框架的风险管理与免责声明解读
  • kali系统中如何给edge浏览器添加omega插件进行抓包
  • Steam挂刀行情站:分布式架构实现多平台饰品价格实时监控与智能分析
  • 基于 YOLOv8 的农作物识别系统数据增强策略对比研究
  • Zigup终极指南:如何轻松管理Zig编译器版本
  • Flutter SliverAppBar:解决滚动界面设计痛点的终极方案
  • 如何高效使用智能招聘时间助手:求职者的精准筛选指南
  • WebODM终极指南:5步搞定无人机图像处理,免费创建专业级三维模型
  • 玻璃清洁机器人
  • STM32F723ZE与M95M04 EEPROM配置存储方案详解
  • 怎样3分钟搞定全网热门资源:终极视频下载神器完全指南
  • R3F-Perf自定义图表开发:扩展监控指标与可视化数据分析
  • 3步实现GLM-5.2-w4a8大模型效能跃升实战解析
  • ChunkHound实时索引指南:自动文件监控与智能差异检测
  • C++ 11 中的并发多线程模式
  • Azure WebJobs SDK部署指南:从本地开发到Azure云服务的完整流程
  • git-peek安全指南:GitHub Token管理与临时文件清理机制
  • 如何为EarlyBird编写自定义检测模块:从零开始创建专属安全规则
  • AI编程行为修正框架:Karpathy原则如何优化LLM编码质量
  • Flashtool深度探索:解锁Sony Xperia设备刷机的终极工具
  • EhViewer开源漫画应用:三步打造个性化阅读空间
  • 如何解决Python asyncio ‘RuntimeError: This event loop is already running‘ 错误:nest_asyncio 终极教程
  • 163MusicLyrics终极指南:一键解决音乐歌词缺失的完整解决方案
  • 底座冲压成形工艺及模具设计