websocket 介绍
目录
- 1,前端如何实现即时通讯
- 短轮询
- 长轮询
- 2,websocket
- 2.1,握手
- 2.2,握手过程举例
- 2.3,socket.io
- 3,websocket 对比 http 的优势
1,前端如何实现即时通讯
在 websocket 协议出现之前,前端想实现即时通讯,只能通过下面2种方式:
- 短轮询 short polling
- 长轮询 long polling
短轮询
客户端每隔一小段时间,就向服务器请求一次,询问有没有新消息。
实现起来很简单,只需要开启一个计时器不断发送请求即可。但缺点比较明显:
- 会产生大量无意义的请求。
- 会频繁打开关闭 TCP 连接。
- 实时性并不高。
长轮询
为了解决短轮询的问题,出现了长轮询。原理如下图:

虽然长轮询让每次请求和响应都变的有意义,但依然存在一些问题:
-
客户端长时间收不到响应会导致超时,从而主动断开和服务器的连接。
可以在 ajax 请求因为超时而结束时,立即重新发送请求到服务器。虽然会让之前的请求无意义,但比短轮询好多了。
-
因为客户端可能【过早的】请求了服务器,所以服务器不得不挂起这个请求,直到新消息出现。
这会让服务器长时间占用资源却没有做任何事情。
2,websocket
websocket 协议 HTML5 带来的新协议,相对于 http,它是一个持久连接的协议,它利用 http 协议完成握手,然后通过 TCP 连接通道发送消息,使用 websocket 协议可以实现服务器主动推送消息的能力。
从上图可以看出:
- websocket 也是建立在 TCP 协议上的,利用的是 TCP 的全双工通信能力。
- 使用时会经过2个阶段,握手阶段和通信阶段。
- 维持 TCP 连接也是需要耗费资源的,所以看实际需求。
2.1,握手
websocket 协议内容比较复杂,这里只介绍下握手协议。(下面会有例子说明)
当客户端需要和服务器使用 websocket 进行通信时,首先会使用HTTP协议完成一次特殊的请求-响应,这一次的请求-响应就是websocket握手。
在握手阶段,首先由客户端向服务器发送一个请求,请求地址格式如下:
# 使用 HTTP
ws://mysite.com/path
# 使用 HTTPS
wss://mysite.com/path
请求头:
Connection: Upgrade /* 协议需要升级,不使用 HTTP了 */
Upgrade: websocket /* 协议升级为 websocket */
Sec-WebSocket-Version: 13 /* websocket协议版本为 13 */
Sec-WebSocket-Key: YWJzZmFkZmFzZmRhYw== /* 连接的 key */
服务器如果同意,响应如下消息:
HTTP/1.1 101 Switching Protocols /* 切换协议,101表示切换协议 */
Connection: Upgrade /* 协议升级 */
Upgrade: websocket /* 升级到 websocket */
Sec-WebSocket-Accept: ZzIzMzQ1Z2V3NDUyMzIzNGVy /* 重新编码后的 key */
Sec-WebSocket-Accept 是将 Sec-WebSocket-Key 使用特殊的算法重新编码生成的。浏览器使用它来确保响应与请求相对应。
握手完成后,后续的消息收发不再使用 HTTP,任何一方都可以主动发消息给对方。
2.2,握手过程举例
客户端:
<button>发送数据到服务器</button>
<script>// 创建一个websocket,同时,发送连接到服务器const ws = new WebSocket("ws://localhost:3002"); ws.onopen = function () {// http 握手完成console.log("连接已建立");};ws.onclose = function () {console.log("通道关闭");};document.querySelector("button").onclick = function () {ws.send("客户端数据123");};// ws.close(); //客户端主动断开连接
</script>
服务器:
const net = require("net");const server = net.createServer((socket) => {console.log("收到客户端的连接");socket.once("data", (chunk) => {// 解析请求报文,const httpContent = chunk.toString("utf-8");let parts = httpContent.split("\r\n");parts.shift();parts = parts.filter((s) => s).map((m) => {const i = m.indexOf(":");return [m.slice(0, i), m.slice(i + 1).trim()];});// 变成对象的形式,为了取出请求头 Sec-WebSocket-Keyconst headers = Object.fromEntries(parts);const crypto = require("crypto"); // 加密模块const hash = crypto.createHash("sha1");// 创建 Sec-WebSocket-Accept,后面是一个随机的 guid。const key = hash.update(headers["Sec-WebSocket-Key"] + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest("base64");// 响应,注意格式。socket.write(`HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: ${key}`);// 接收客户端的消息socket.on("data", (chunk) => {console.log(chunk.toString("utf-8"));});});
});server.listen(3002);
注意数据格式为 Buffer 需要转码,因为 websocket 的消息需要特定的格式,数据量较大时会切片传输。但每个切片到达的顺序可能不一样,所以为了保证将接收到的数据,能按照顺序拼接,所以数据格式为 Buffer 二进制的形式。
2.3,socket.io
一般使用 websocket 大多都会使用它 socket.io
测试使用版本 v4.7.2,消息格式都是字符串而不是 Buffer,所以不用转码了。
浏览器:访问地址 http://localhost:5500/index.html
<button>发送数据到服务器</button>
<script src="https://cdn.bootcdn.net/ajax/libs/socket.io/4.7.2/socket.io.js"></script>
<script>const socket = io("http://localhost:3002");document.querySelector("button").onclick = function () {socket.emit("to-server", "来自浏览器的消息");};// 监听服务器的消息,约定事件名 to-clientsocket.on("to-client", (chunk) => {console.log(chunk);});// 服务器断开连接时触发socket.on("disconnect", () => {console.log("closed");});
</script>
服务器:写法参考
启动后的服务器地址:http://localhost:3002,所以会发生跨域。解决
const Koa = require("koa");
const { createServer } = require("http");
const { Server } = require("socket.io");const app = new Koa();
const httpServer = createServer(app.callback());
const io = new Server(httpServer, {cors: {origin: "http://localhost:5500",},
});io.on("connection", (socket) => {// 当有一个新的客户端连接到服务器成功之后,触发的事件console.log("新的客户端连接进来了");// 监听客户端发送的消息,约定事件为 to-serversocket.on("to-server", (chunk) => {// 监听客户端的msg消息console.log(chunk);});let count = 0;const timer = setInterval(function () {// 每隔两秒钟,发送一个消息给客户端,约定事件为 to-clientsocket.emit("to-client", `来自服务器的第${count++}次消息`);}, 2000);socket.on("disconnect", () => {clearInterval(timer);console.log("closed");});
});// 监听端口
httpServer.listen(3002, () => {console.log("server listening on 3002");
});
效果展示:

3,websocket 对比 http 的优势
当页面中需要观察实时数据的变化(比如聊天、k 线图)时,过去我们往往使用两种方式完成(短轮询,长轮询)
无论是哪一种方式,都暴露了 http 协议的弱点,即响应必须在请求之后发生,服务器是被动的,无法主动推送消息。而让客户端不断的发起请求又会占用了资源。
websocket 的出现就是为了解决短轮询,长轮询的缺点,它利用 http 协议完成握手之后,就可以与服务器建立持久的连接,服务器可以在需要的时候主动推送消息给客户端,这样占用的资源最少,同时实时性也最高。
以上。
相关文章:
websocket 介绍
目录 1,前端如何实现即时通讯短轮询长轮询 2,websocket2.1,握手2.2,握手过程举例2.3,socket.io 3,websocket 对比 http 的优势 1,前端如何实现即时通讯 在 websocket 协议出现之前,…...
【IoT网络层】STM32 + ESP8266 +MQTT + 阿里云物联网平台 |开源,附资料|
目标:实现STM32连接阿里云物联网平台发送数据同时接收数据,IOT studio界面显示数据。具体来说:使用ESP8266 ESP-01来连接网络,获取设备数据发送到阿里云物联网平台并显示且oled显示屏当前的设备数据,通过IOT studio界面…...
数据分析工具 Top 8
你能想象一个没有工具箱的水管工吗? 没有,对吧? 数据从业者也是如此。如果没有他们的数据分析工具,数据从业者就无法分析数据、可视化数据、从数据中提取价值,也无法做数据从业者在日常工作中做的许多很酷的事情。 根据你最感兴趣的数据科学职业——数…...
AI 换脸的新时代:没有显卡也可以使用的AI换脸工具
大家好!今天,我要为大家介绍一个即使没有显卡,也能体验AI换脸的工具!是的,您没听错,无论您的电脑配置如何,只要运行在Windows 10或Windows 11上,都可以轻松使用这一神奇工具。这就是…...
3.Python中的循环结构
Python中的循环结构 一、回顾分支练习题 1、判断是否为一个合法三角形 需求:输入三角形的3边,如果两边的长度大于第三条边,则代表是一个合法三角形 # 1、提示用户输入三角形的三边长度 a = int(input(请输入第一条边的长度:)) b = int(input(请输入第二条边的长度:)) …...
机器学习之BP神经网络精讲(Backpropagation Neural Network(附案例代码))
概念 BP神经网络(Backpropagation Neural Network)是一种常见的人工神经网络,它通过反向传播算法来训练网络,调整连接权重以最小化预测输出与实际输出之间的误差。这种网络结构包含输入层、隐藏层和输出层,使用梯度下降算法来优化权重。 结构: BP神经网络(Backpropag…...
安全生产人员定位系统助企业实现智能化管理,提高生产安全性和效率
安全生产人员定位系统是基于物联网技术的系统,通过集成各种传感器和通信技术,实时监测员工的位置和活动状态。该系统可以帮助企业管理者了解员工的工作状态,及时发现潜在的安全隐患,从而采取相应的措施,保障员工的安全…...
动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本
涉及知识点 动态规划 多源最短路径 字典树 题目 给你两个下标从 0 开始的字符串 source 和 target ,它们的长度均为 n 并且由 小写 英文字母组成。 另给你两个下标从 0 开始的字符串数组 original 和 changed ,以及一个整数数组 cost ,其中…...
Hadoop集群找不到native-hadoop
1.问题描述 hive 运行中的问题,需要把把native复制进去 /usr/lib 2023-02-15 19:59:42,165 WARN scheduler.TaskSetManager: Lost task 11.0 in stage 1.0 (TID 3, common4, executor 2): java.lang.RuntimeException: Hive Runtime Error while closing operators…...
解决阿里云远程连接yum无法安装问题(Ubuntu 22.04)
解决阿里云远程连接yum无法安装问题(Ubuntu 22.04) 第一步 进入阿里云远程连接后,尝试安装宝塔面包第二步:尝试更新软件包等一些列操作第三步:完成上述操作之后,尝试安装yum第四步:尝试更换清华…...
springboot 查询
ServiceImpl中 getBaseMapper()的使用 public IPage<ProductPageVO> getProductPage(Integer regionOrCityCode, Integer brandId, LocalDate usedDate, Page<ProductPageVO> page) {return getBaseMapper().getProductPage(regionOrCityCode, brandId, usedDate, …...
【分布式链路追踪技术】sleuth+zipkin
目录 1.概述 2.搭建演示工程 3.sleuth 4.zipkin 5.插拔式存储 5.1.存储到MySQL中 5.2.用MQ来流量削峰 6.联系作者 1.概述 当采用分布式架构后,一次请求会在多个服务之间流转,组成单次调用链的服务往往都分散在不同的服务器上。这就会带来一个问…...
Windows 源码编译 MariaDB
环境 Win11, vs2022, git, cmake, Bison from GnuWin32, perl, Gnu Diff. 默认都安装好。 perl 看之前博客教程。perl Bison from GnuWin32 默认安装到 C:\GnuWin32 Add C:\GnuWin32\bin to your system PATH after installation. 下载mariadb源码 地址:MariaD…...
【动画视频生成】
转自:机器之心 动画视频生成这几天火了,这次 NUS、字节的新框架不仅效果自然流畅,还在视频保真度方面比其他方法强了一大截。 最近,阿里研究团队构建了一种名为 Animate Anyone 的方法,只需要一张人物照片࿰…...
《Spring Cloud学习笔记:微服务保护Sentinel》
Review 解决了服务拆分之后的服务治理问题:Nacos解决了服务治理问题OpenFeign解决了服务之间的远程调用问题网关与前端进行交互,基于网关的过滤器解决了登录校验的问题 流量控制:避免因为突发流量而导致的服务宕机。 隔离和降级:…...
解密负载均衡:如何平衡系统负载(下)
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...
go 源码解读 - sync.Mutex
sync.Mutex mutex简介mutex 方法源码标志位获取锁LocklockSlowUnlock怎么 调度 goroutineruntime 方法 mutex简介 mutex 是 一种实现互斥的同步原语。(go-version 1.21) (还涉及到Go运行时的内部机制)mutex 方法 Lock() 方法用于…...
机器学习系列--R语言随机森林进行生存分析(1)
随机森林(Breiman 2001a)(RF)是一种非参数统计方法,需要没有关于响应的协变关系的分布假设。RF是一种强大的、非线性的技术,通过拟合一组树来稳定预测精度模型估计。随机生存森林(RSF࿰…...
<JavaEE> TCP 的通信机制(四) -- 流量控制 和 拥塞控制
目录 TCP的通信机制的核心特性 五、流量控制 1)什么是“流量控制”? 2)如何做到“流量控制”? 3)“流量控制”的作用 六、拥塞控制 1)什么是“拥塞控制”? 2)如何做到“拥塞…...
智慧监控平台/AI智能视频EasyCVR接口调用编辑通道详细步骤
视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,在视频监控播放上,GB28181视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放,可同时播放多路视频流,…...
Qwen3-14B私有化效果:支持国密算法加密的API通信安全方案
Qwen3-14B私有化效果:支持国密算法加密的API通信安全方案 1. 私有部署镜像概述 Qwen3-14B私有部署镜像是基于通义千问大语言模型优化定制的专业解决方案,特别针对RTX 4090D 24GB显存配置进行了深度适配。这个镜像不仅提供了完整的运行环境和模型依赖&a…...
gh_mirrors/eg/eggs深度解析:一站式解决所有服务器部署难题
gh_mirrors/eg/eggs深度解析:一站式解决所有服务器部署难题 【免费下载链接】eggs Service eggs for the pterodactyl panel 项目地址: https://gitcode.com/gh_mirrors/eg/eggs 在服务器管理领域,快速部署和高效运维一直是开发者和管理员面临的核…...
告别Transformer的O(n²)烦恼:手把手带你用Mamba-2.0搭建一个长文本摘要模型
突破长文本处理瓶颈:基于Mamba-2.0的高效摘要系统实战指南 在当今信息爆炸的时代,我们每天都被海量文本内容包围——从学术论文、技术文档到商业报告,这些长文本的有效处理已成为知识工作者面临的核心挑战。传统基于Transformer的摘要系统虽然…...
RK3588中使用Serial转发订阅的话题数据
我们在ROS的使用中,常常会通过rostopic echo /***来订阅某个话题数据的输出,我想通过串口对其通串口进行转发。#查看ros话题列表 rostopic list 找到一个你想要订阅的话题如/IMU_data#订阅话题通过终端查看 rostopic echo /IMU_data就会看到以下这种数据…...
嵌入式电子罗盘教学原型:磁力计与IMU传感器融合实践
1. 项目概述 “LCD-Ecompass-Postemsky”是一个面向嵌入式教学实践的简易电子罗盘(E-Compass)系统,由阿根廷圣路易斯国立大学(Universidad Nacional de San Luis, UNSL)电子工程系为本科生实验课程设计。项目名称中的“…...
从脑电波到股票K线:EMD经验模态分解在5个真实场景下的避坑指南
从脑电波到股票K线:EMD经验模态分解在5个真实场景下的避坑指南 当你第一次看到脑电波信号与股票K线图被放在同一个分析框架下讨论时,可能会觉得这是两个毫不相关的领域。但事实上,无论是神经科学家的EEG数据,还是量化交易员的股价…...
记一次攻防演练复盘(蓝队)
事件:某省大数据局主导的一次攻防演练中午时段遭受大量攻击。 告警信息(TOP 5):[疑似目录穿越攻击URI] [漏洞攻击: Apache log4j RCE Attempt (http ldap) (CVE-2021-44228)] [web路径遍历漏洞攻击-Linux环境] [XSS跨站脚本攻击U…...
Splitting.js创意指南:让网页文字动起来的实用技巧
Splitting.js创意指南:让网页文字动起来的实用技巧 【免费下载链接】Splitting JavaScript microlibrary to split an element by words, characters, children and more, populated with CSS variables! 项目地址: https://gitcode.com/gh_mirrors/sp/Splitting …...
Vita3K终极指南:在PC上完美运行PSVita游戏的完整教程
Vita3K终极指南:在PC上完美运行PSVita游戏的完整教程 【免费下载链接】Vita3K Experimental PlayStation Vita emulator 项目地址: https://gitcode.com/gh_mirrors/vi/Vita3K 想在电脑上重温PSVita经典游戏吗?Vita3K模拟器为你打开了一扇通往掌机…...
FDTD仿真中谐振腔Q值计算:从低Q到高Q的完整实践指南
1. 谐振腔Q值计算的核心概念 第一次接触谐振腔Q值计算时,我被各种公式和图表搞得晕头转向。直到在实验室熬了三个通宵后,才真正理解Q值就像是一个"能量储存能力"的评分卡——分数越高,能量泄漏越慢。在FDTD仿真中,我们…...
