漫扯:从polling到Websocket
漫扯从 Polling 到 WebSocket在互联网的早期服务器与客户端之间的通信主要依赖于“请求-响应”模式客户端发送请求服务器返回响应。然而随着实时应用如聊天、股票行情推送、协作编辑的兴起这种模式显得捉襟见肘——它无法让服务器主动向客户端推送数据。为了解决这个问题开发者们发明了各种“变通”方案其中最具代表性的就是Polling轮询和WebSocket。本文将带你从底层原理出发逐步揭开从轮询到 WebSocket 的进化之路。## 一、Polling一种“笨拙”的实时方案### 1.1 短轮询Short Polling短轮询是最简单的“实时”模拟方案。客户端每隔固定时间如1秒向服务器发送 HTTP 请求询问是否有新数据。服务器无论是否有新数据都会立即响应。工作原理- 客户端setInterval(() fetch(/data), 1000)- 服务器接收到请求后检查数据是否更新返回结果。问题- 浪费带宽许多请求返回的是“无新数据”但完整 HTTP 头部仍被传输。- 延迟不可控假设数据在第 500ms 更新客户端需要等到下一轮请求第 1000ms才能获取平均延迟为轮询间隔的一半。- 服务器压力大量短时连接会造成服务器资源浪费。### 1.2 长轮询Long Polling为了解决短轮询的延迟问题长轮询应运而生。客户端发送请求后服务器会挂起该连接直到有新数据时才返回。如果长时间无数据服务器会返回超时响应客户端立即重新发起请求。工作原理- 客户端发送请求后不立即断开连接而是等待服务器响应。- 服务器收到请求后如果无新数据则阻塞连接不返回直到数据可用或超时。- 一旦返回客户端立即再次发起请求。优点延迟大大降低数据产生后即可返回。缺点- 仍然需要频繁建立和关闭连接即使使用了 Keep-Alive。- 服务器需要维护大量挂起的连接消耗内存和线程资源。- 无法实现真正的双向通信服务器只能在响应中推送数据。### 代码示例短轮询 vs 长轮询Python 伪代码python# 示例1短轮询的客户端与服务器实现基于 Flask requests# 注意此代码仅为演示原理非生产级实现import timeimport threadingfrom flask import Flask, jsonify, requestimport requestsapp Flask(__name__)# 模拟共享数据假设由另一个线程更新data_store {value: 初始数据}lock threading.Lock()# 模拟数据更新线程def update_data(): global data_store time.sleep(5) # 5秒后更新数据 with lock: data_store[value] 新数据app.route(/short_poll, methods[GET])def short_poll(): 短轮询端点直接返回当前数据 with lock: return jsonify({data: data_store[value]})# 客户端模拟def client_short_poll(): for i in range(10): resp requests.get(http://127.0.0.1:5000/short_poll) print(f第{i1}次轮询: {resp.json()}) time.sleep(1) # 每1秒轮询一次# 启动数据更新线程threading.Thread(targetupdate_data, daemonTrue).start()if __name__ __main__: # 启动客户端线程仅演示 threading.Thread(targetclient_short_poll, daemonTrue).start() app.run(port5000)长轮询的简化实现仅展示核心差异点python# 示例2长轮询的服务器端使用 Flask模拟阻塞# 注意Flask 默认是同步的挂起连接会阻塞线程生产环境需使用异步框架from flask import Flask, jsonify, requestimport timeapp Flask(__name__)# 模拟数据初始为 None等待外部设置data Noneapp.route(/long_poll, methods[GET])def long_poll(): 长轮询端点如果没有新数据则等待最多30秒 global data timeout 30 # 超时时间秒 start_time time.time() # 模拟等待新数据实际场景中应使用事件队列、条件变量等 while time.time() - start_time timeout: if data is not None: # 返回数据并清空缓存 response jsonify({data: data}) data None return response # 休眠一小段时间避免忙等待CPU 空转 time.sleep(0.5) # 超时返回空响应 return jsonify({error: timeout}), 204if __name__ __main__: app.run(port5000)## 二、WebSocket真正的全双工通信### 2.1 原理剖析WebSocket 是 HTML5 引入的协议RFC 6455它基于 HTTP 进行握手然后升级为独立的 TCP 连接实现客户端与服务器之间的全双工通信。握手过程1. 客户端发送 HTTP 请求包含Upgrade: websocket和Sec-WebSocket-Key随机字符串。2. 服务器计算Sec-WebSocket-Accept基于 Key 和固定 GUID 的 SHA-1 哈希返回101 Switching Protocols。3. 连接升级成功之后双方可以互相发送帧Frame数据。帧结构WebSocket 数据以帧为单位传输包含操作码如文本帧、二进制帧、关闭帧、掩码客户端到服务器必须掩码、有效载荷长度等。优势-低延迟数据产生后服务器可立即推送无需等待客户端请求。-低开销建立连接后不再需要 HTTP 头部帧头仅 2-14 字节。-双向通信客户端和服务器都可以主动发送消息。### 2.2 代码示例使用 Python 实现 WebSocket 服务器python# 示例3基于 websockets 库的 WebSocket 服务器与客户端# 安装pip install websocketsimport asyncioimport websockets# 存储连接的客户端connected_clients set()async def handler(websocket, path): 处理每个 WebSocket 连接 # 将新客户端加入集合 connected_clients.add(websocket) try: async for message in websocket: # 收到客户端消息后广播给所有其他客户端 print(f收到消息: {message}) # 回复客户端回声 await websocket.send(f服务器已收到: {message}) # 同时广播给其他客户端模拟实时聊天 for client in connected_clients: if client ! websocket: await client.send(f广播: {message}) except websockets.ConnectionClosed: print(客户端断开连接) finally: # 移除断开的客户端 connected_clients.remove(websocket)async def main(): # 启动 WebSocket 服务器监听本地 8765 端口 async with websockets.serve(handler, localhost, 8765): print(WebSocket 服务器已启动地址: ws://localhost:8765) await asyncio.Future() # 保持服务器运行if __name__ __main__: asyncio.run(main())客户端示例浏览器或 Python 均可python# 示例4Python WebSocket 客户端import asyncioimport websocketsasync def chat(): uri ws://localhost:8765 async with websockets.connect(uri) as websocket: # 发送消息 await websocket.send(Hello, 服务器!) # 接收响应 response await websocket.recv() print(f服务器回复: {response})asyncio.run(chat())## 三、从 Polling 到 WebSocket技术演进总结| 特性 | 短轮询 | 长轮询 | WebSocket ||--------------|----------------------|----------------------|---------------------|| 通信方向 | 客户端→服务器 | 客户端→服务器可延迟响应 | 全双工双向实时 || 延迟 | 高~轮询间隔/2 | 低数据产生后立即返回 | 极低无额外延迟 || 带宽开销 | 高频繁 HTTP 请求 | 中连接挂起但仍需头部 | 低帧头极小 || 服务器资源 | 轻量连接短暂 | 重量需维护大量挂起连接 | 轻量长连接异步处理 || 实现复杂度 | 简单 | 中等需处理超时和状态 | 中等需升级握手 |## 总结从短轮询到长轮询再到 WebSocket这不仅是技术的演变更是对“实时性”需求的回应。短轮询如同一个不断打电话问“有消息吗”的人长轮询像是“你挂电话等有消息再打给我”而 WebSocket 则是“电话接通后我们可以随时说话”。虽然 Polling 在特定场景下仍有价值如简单的状态检查但 WebSocket 已成为实时应用的事实标准。理解它们的原理能帮助我们在面对不同的业务需求时做出更明智的技术选型。

相关新闻

TripoSF高级配置详解:如何调整参数实现最佳3D重建效果

TripoSF高级配置详解:如何调整参数实现最佳3D重建效果

TripoSF高级配置详解:如何调整参数实现最佳3D重建效果 【免费下载链接】TripoSF SparseFlex: High-Resolution and Arbitrary-Topology 3D Shape Modeling 项目地址: https://gitcode.com/gh_mirrors/tr/TripoSF TripoSF是一款强大的3D形状建模工具&#xff…

2026/7/26 21:27:13 阅读更多 →
Unity Dynamic Bone胸部物理抖动:从原理到调优的完整避坑指南

Unity Dynamic Bone胸部物理抖动:从原理到调优的完整避坑指南

1. 项目概述:从“会动”到“动得对”在Unity中实现角色胸部等部位的物理抖动效果,Dynamic Bone 1.3.4版本曾是一个被广泛使用的经典插件。它通过简化的弹簧质点模型,为骨骼链添加了柔和的物理模拟,让角色的头发、尾巴、衣物&#…

2026/7/26 21:27:13 阅读更多 →
深度传感器如何与PX4-Avoidance协同工作?Realsense D435实战指南

深度传感器如何与PX4-Avoidance协同工作?Realsense D435实战指南

深度传感器如何与PX4-Avoidance协同工作?Realsense D435实战指南 【免费下载链接】PX4-Avoidance PX4 avoidance ROS node for obstacle detection and avoidance. 项目地址: https://gitcode.com/gh_mirrors/px/PX4-Avoidance PX4-Avoidance是一个基于ROS的…

2026/7/26 21:26:12 阅读更多 →

最新新闻

用户说“挺好”,数据却显示流失率飙升?(揭秘AI满意度分析中被忽视的3层语义鸿沟)

用户说“挺好”,数据却显示流失率飙升?(揭秘AI满意度分析中被忽视的3层语义鸿沟)

更多请点击: https://codechina.net 第一章:用户说“挺好”,数据却显示流失率飙升?(揭秘AI满意度分析中被忽视的3层语义鸿沟) 当客服系统记录下用户最后一句“挺好,谢谢”,CRM 却标…

2026/7/26 21:53:25 阅读更多 →
StaffDeck API完全参考:打造无缝集成的企业应用生态

StaffDeck API完全参考:打造无缝集成的企业应用生态

StaffDeck API完全参考:打造无缝集成的企业应用生态 【免费下载链接】StaffDeck Enterprise Digital Employee Platform 项目地址: https://gitcode.com/gh_mirrors/st/StaffDeck StaffDeck作为企业级数字员工平台,提供了全面的API接口&#xff0…

2026/7/26 21:53:25 阅读更多 →
Trifle开源分析工具:从存储事件到存储答案的架构革新

Trifle开源分析工具:从存储事件到存储答案的架构革新

那天下午,团队里的产品经理又来找我:“我们上周上线的那个新功能,用户到底有没有在用?能不能看看点击率?”我打开数据分析后台,熟练地筛选时间范围、选择事件类型,然后看着屏幕上跳出来的数字陷…

2026/7/26 21:53:25 阅读更多 →
Unity游戏开发中C#解构函数的实用指南与最佳实践

Unity游戏开发中C#解构函数的实用指南与最佳实践

1. 项目概述:为什么Unity开发者需要关注C#解构函数在Unity游戏开发中,我们每天都在和各种各样的数据结构打交道:从Vector3、Color这样的内置类型,到自定义的PlayerData、InventoryItem等复杂类。处理这些数据时,一个高…

2026/7/26 21:53:25 阅读更多 →
维修电工职业资格考证全攻略:从入门到取证

维修电工职业资格考证全攻略:从入门到取证

1. 维修电工行业背景与职业前景 电力作为现代社会运转的基础能源,维修电工已成为工业生产、建筑施工、物业维护等领域不可或缺的技术工种。随着我国电力基础设施的持续升级和智能电网建设的推进,具备专业资质的维修电工人才需求呈现稳定增长态势。 根据…

2026/7/26 21:53:25 阅读更多 →
5个颠覆性功能:重新定义Python GUI开发体验

5个颠覆性功能:重新定义Python GUI开发体验

5个颠覆性功能:重新定义Python GUI开发体验 【免费下载链接】tkinter-helper 为tkinter打造的可视化拖拽布局界面设计小工具 项目地址: https://gitcode.com/gh_mirrors/tk/tkinter-helper 还在为Tkinter界面开发而反复调试代码吗?想象一下&#…

2026/7/26 21:52:25 阅读更多 →

日新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/26 0:00:31 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/26 0:00:31 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/26 0:00:31 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/26 0:00:31 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/26 0:00:31 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/26 0:00:31 阅读更多 →

月新闻