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 协议完成握手之后,就可以与服务器建立持久的连接,服务器可以在需要的时候主动推送消息给客户端,这样占用的资源最少,同时实时性也最高。


以上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/225793.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无需手动搜索!轻松创建IntelliJ IDEA快捷方式的Linux教程

轻松创建IntelliJ IDEA快捷方式的Linux教程 一、IntelliJ IDEA简介二、在Linux系统中创建快捷方式的好处三、命令行创建IntelliJ IDEA快捷方式四、图形界面创建IntelliJ IDEA快捷方式五、常见问题总结 一、IntelliJ IDEA简介 IntelliJ IDEA是一个由JetBrains搞的IDE&#xff0…

vue3+luckyexcel+php在线编辑excel文件

开发过程中&#xff0c;需要开发一个在线编辑excel文档的功能&#xff0c;找到了这个合适的组件 Luckysheet &#xff0c;一款纯前端类似excel的在线表格&#xff0c;功能强大、配置简单、完全开源。 可以导入文档&#xff0c;预览、编辑、保存、导出等功能&#xff0c;可以满…

侦探IP“去推理化”:《名侦探柯南》剧场版走过26年

2023年贺岁档&#xff0c;柯南剧场版的第26部《黑铁的鱼影》如期上映。 这部在日本狂卷票房128亿日元的作品&#xff0c;被誉为有史以来柯南剧场版在商业成绩上最好的一部。 但该作在4月份日本还未上映前&#xff0c;就于国内陷入了巨大的争议。 试映内容里&#xff0c;灰原…

Android原生实现分段选择

六年前写的一个控件&#xff0c;一直没有时间总结&#xff0c;趁年底不怎么忙&#xff0c;整理一下之前写过的组件。供大家一起参考学习。废话不多说&#xff0c;先上图。 一、效果图 实现思路使用的是radioGroup加radiobutton组合方式。原理就是通过修改RadioButton 的backgr…

云计算:OpenStack 配置二层物理网卡为三层桥的接口

目录 一、理论 1.OpenStack 二、实验 1. Linux系统修改网卡 2.OpenStack 配置二层物理网卡为三层桥的接口 一、理论 1.OpenStack &#xff08;1&#xff09;概念 OpenStack是一个开源的云计算管理平台项目&#xff0c;是一系列软件开源项目的组合。由NASA(美国国家航空…

为什么要运营海外社媒?海外云手机能发挥什么作用?

基于海外社媒在全球范围内拥有的大量流量&#xff0c;海外社媒运营成为了品牌推广、内容创作和用户互动的重要途径。本文将探讨海外社媒运营的重要性&#xff0c;并介绍海外云手机在这一过程中的卓越帮助。 海外社媒运营的重要性 首先&#xff0c;海外社媒运营有助于企业扩大品…

学习笔记:数据挖掘与机器学习

文章目录 一、数据挖掘、机器学习、深度学习的区别&#xff08;一&#xff09;数据挖掘&#xff08;二&#xff09;机器学习&#xff08;三&#xff09;深度学习&#xff08;四&#xff09;总结 二、数据挖掘体系三、数据挖掘的流程四、典型的数据挖掘系统 一、数据挖掘、机器学…

卷积神经网络 反向传播

误差的计算 softmax 经过softmax处理后所有输出节点概率和为1 损失&#xff08;激活函数&#xff09; 多分类问题&#xff1a;输出只可能归于某一个类别&#xff0c;不可能同时归于多个类别。 误差的反向传播 求w的误差梯度 权值的更新 首先是更新输出层和隐藏层之间的权重…

SMART PLC编码器长度测量功能块

SMART PLC编码器转速测量功能块详细算法和源代码&#xff0c;请参考下面文章链接&#xff1a; https://rxxw-control.blog.csdn.net/article/details/134375193https://rxxw-control.blog.csdn.net/article/details/134375193SMART PLC编码器线速度测量功能块算法和源代码请参…

【数据结构和算法】寻找数组的中心下标

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 前缀和的解题模板 2.1.1 最长递增子序列长度 2.1.2 寻找数组中第 k 大的元素 2.1.3 最长公共子序列…

[C/C++]排序算法 快速排序 (递归与非递归)

目录 &#x1f6a9;概念: &#x1f6a9;实现: ⚡1.hoare ⚡2.挖坑法 ⚡3.双指针法 &#x1f6a9;快速排序递归实现 &#x1f6a9;快速排序非递归实现 &#x1f6a9;概念: 通过一趟排序将要排序的数据分割成独立的两部分&#xff0c;其中一部分的所有数据比另一部分的所有…

【论文解读】Learning based fast H.264 to H.265 transcoding

时间&#xff1a; 2015 年 级别&#xff1a; APSIPA 机构&#xff1a; 上海电力大学 摘要 新提出的视频编码标准HEVC (High Efficiency video coding)以其比H.264/AVC更好的编码效率&#xff0c;被工业界和学术界广泛接受和采用。在HEVC实现了约40%的编码效率提升的同时&…

oracle下载

前言&#xff1a; 官网上提供都是最新的什么19c 21c这些版本&#xff0c;我要的是 11g 12c 或者更老的 8i 9i 这些版本。 准备下载一个oracle12c 版本&#xff0c;但是找了很久&#xff0c;最终…详情请看下面 oracle 数据库版本介绍 Oracle数据库有多个长期支持版本&#x…

LabVIEW在横向辅助驾驶系统开发中的应用

LabVIEW在横向辅助驾驶系统开发中的应用 随着横向辅助驾驶技术的快速发展&#xff0c;越来越多的研究致力于提高该系统的效率和安全性。项目针对先进驾驶辅助系统&#xff08;ADAS&#xff09;中的横向辅助驾驶进行深入研究。在这项研究中&#xff0c;LabVIEW作为一个强大的系…

LDO线性稳压器与开关电源的原理

线性稳压器LDO典型代表&#xff1a;LM7805 ,AMS1117&#xff0c;还有一下性能比较好的LDO&#xff1a; 开关稳压器典型代表&#xff1a;LM2596&#xff0c;MP1584,TPS5430&#xff0c;MP2315S LDO靠发热分散能量&#xff0c;纹波较小一般在30mv以下&#xff1b;DCDC通过开关开断…

嵌入式单片机的存储区域与堆和栈

一、单片机存储区域 如图所示位STM32F103ZET6的参数&#xff1a; 单片机的ROM&#xff08;内部FLASH&#xff09;&#xff1a;512KB&#xff0c;用来存放程序代码的空间。 单片机的RAM&#xff1a;64KB&#xff0c;一般都被分配为堆、栈、变量等的空间。 二、堆和栈的概念 …

[SWPUCTF 2021 新生赛]finalrce

[SWPUCTF 2021 新生赛]finalrce wp 注&#xff1a;本文参考了 NSSCTF Leaderchen 师傅的题解&#xff0c;并修补了其中些许不足。 此外&#xff0c;参考了 命令执行(RCE)面对各种过滤&#xff0c;骚姿势绕过总结 题目代码&#xff1a; <?php highlight_file(__FILE__); …

运动障碍疾病常用量表汇总,赶快收藏!

根据神经内科医生的量表使用情况&#xff0c;常笑医学整理了神经内科临床上常用的运动障碍疾病评估量表&#xff0c;均支持量表下载和在线使用&#xff0c;建议收藏&#xff01; 1.统一帕金森病评定量表(UPDRS 3.0版) 统一帕金森病评定量表(UPDRS 3.0版)-常笑医学网​http://w…

小狐狸GPT付费2.4.9 去除授权弹窗版

后台安装步骤&#xff1a; 1、在宝塔新建个站点&#xff0c;php版本使用7.2 、 7.3 或 7.4&#xff0c;把压缩包上传到站点根目录&#xff0c;运行目录设置为/public 2、导入数据库文件&#xff0c;数据库文件是 /db.sql 3、修改数据库连接配置&#xff0c;配置文件是/.env 4、…

对于c++的总结与思考

笔者觉得好用的学习方法&#xff1a;模板法 1.采用原因&#xff1a;由于刚从c语言面向过程的学习中解脱出来&#xff0c;立即把思路从面向过程转到面向对象肯定不现实&#xff0c;加之全新的复杂语法与操作&#xff0c;着实给新手学习这门语言带来了不小的困难。所以&#xff…