即时通信的方法和webSocket的具体使用
前言
之前遇到过需要即时通讯的场景,刚开始使用的是通过轮询的方式,定时器3秒向服务器请求一次数据,后面发现如果在手机端长时间打开使用此功能的页面,可能会发生手机发热,甚至卡顿的现象。最后改用webSocket,可以实现全双工通信,让服务器主动向客户端发送请求。
接下来先介绍一下即时通信的实现方法?
-
轮询(Polling):
- 工作原理:客户端定时向服务器发送请求,询问是否有新数据可用。如果服务器有新数据,返回数据;如果没有,服务器返回空响应。客户端收到响应后立即再次发送请求,形成周期性的轮询过程。
- 优点:实现简单,大部分浏览器和服务器都支持。
- 缺点:频繁的请求和响应会导致不必要的网络开销,降低性能和效率。
- 适用场景:适用于数据更新频率不高且实时性要求不高的场景。
-
长轮询(Long Polling):
- 工作原理:客户端发送请求给服务器,服务器不立即返回响应,而是将请求挂起,等待有新数据时再返回响应。一旦客户端收到响应,立即再次发送请求,形成新的挂起请求。
- 优点:相较于轮询,减少了不必要的网络请求,降低了网络开销。
- 缺点:服务器需要维护大量挂起的请求,占用资源较多,不适用于高并发场景。
- 适用场景:适用于数据更新不频繁,但要求实时性相对较高的场景。
-
WebSocket:
- 工作原理:WebSocket 是一种全双工通信协议,通过建立持久性的连接,客户端和服务器可以随时发送和接收消息。连接建立后,双方可以直接发送消息,不需要频繁的握手过程。
- 优点:实现实时通信,降低了不必要的网络开销,性能高,支持跨域通信。
- 缺点:需要服务器和客户端都支持 WebSocket 协议。
- 适用场景:适用于需要实时通信的场景,如实时聊天、在线游戏等。
-
Server-Sent Events(SSE):
- 工作原理:SSE 是一种单向通信协议,允许服务器向客户端发送数据,但客户端不能向服务器发送数据。客户端通过
EventSource对象订阅服务器的事件流,一旦有新数据可用,服务器会自动发送数据给客户端。 - 优点:实现简单,不需要像 WebSocket 那样进行双向握手,适用于服务器向客户端推送数据。
- 缺点:只支持单向通信,不适用于客户端向服务器发送请求。
- 适用场景:适用于服务器主动向客户端推送实时数据的场景,如推送通知、实时监控等。
- 工作原理:SSE 是一种单向通信协议,允许服务器向客户端发送数据,但客户端不能向服务器发送数据。客户端通过
前端如何使用 WebSocket?
在前端中使用 WebSocket 非常简单,首先需要在浏览器中创建一个 WebSocket 对象,然后通过该对象与服务器建立连接。一旦连接建立成功,前端可以通过发送和接收消息来实现与服务器的实时通信。
1. 创建 WebSocket 对象
在 JavaScript 中,可以通过以下代码创建 WebSocket 对象:
const socket = new WebSocket('ws://example.com'); // 根据实际情况替换为服务器的 WebSocket 地址
在上述代码中,我们创建了一个 WebSocket 对象,传入服务器的 WebSocket 地址作为参数。WebSocket 地址的协议可以是 ws(未加密)或 wss(加密)。
2. 监听事件
一旦 WebSocket 连接建立成功,就可以通过监听事件来处理连接状态和消息的收发。
socket.onopen = () => {console.log('WebSocket连接已建立');
};socket.onmessage = event => {const message = event.data;console.log('收到消息:', message);
};socket.onclose = () => {console.log('WebSocket连接已关闭');
};socket.onerror = error => {console.error('WebSocket连接错误:', error);
};
在上述代码中,我们监听了 onopen 事件(连接建立)、onmessage 事件(收到消息)、onclose 事件(连接关闭)、onerror 事件(连接错误)。每当相应的事件触发时,我们通过回调函数来处理相应的逻辑。
3. 发送和接收消息
一旦 WebSocket 连接建立成功,就可以通过 send() 方法来发送消息,同时通过 onmessage 事件来接收消息。
// 发送消息
socket.send('Hello, WebSocket!');// 接收消息在上面的监听代码中已经处理
以上代码演示了如何在前端中创建 WebSocket 连接、发送和接收消息。当服务器和客户端建立连接后,它们可以随时通过 send() 方法和 onmessage 事件来实现实时通信。
4.websocket的心跳机制
WebSocket中心跳机制的作用主要有以下几个方面:
-
保持连接活跃:
WebSocket是一种双向通信协议,一旦建立连接,服务器和客户端之间可以实时传输数据。但由于网络等原因,长时间没有数据传输可能导致连接的关闭。心跳机制通过定期发送心跳包,即使没有实际数据交互,也能保持连接的活跃状态,防止连接被中断。 -
确认服务器存活状态:
通过心跳机制,客户端可以定期向服务器发送心跳包,并等待服务器的响应。如果一段时间内没有收到服务器的响应,客户端可以判断服务器可能出现了故障或断开连接,并根据情况进行相应的处理,如重新连接服务器。 -
优化网络资源利用:
心跳机制可以定时发送较小的数据包,相较于大量数据传输,心跳包的资源占用较小。这有助于减少网络资源的浪费,并提高数据传输效率。 -
错误处理与重连:
通过心跳机制,客户端可以及时检测到连接断开的情况,并进行错误处理和重连操作。在网络环境不稳定或服务器故障的情况下,心跳机制可以帮助客户端更快地恢复与服务器的连接。 -
连接状态监控:
心跳机制可以用于监控WebSocket连接的状态,包括连接建立、断开、异常等状态。这有助于客户端了解连接状态,做出相应的操作。
总体而言,WebSocket中心跳机制的作用是维持连接的稳定性和可靠性,确保连接保持活跃,并及时处理异常情况,提高通信效率和用户体验。
使用:
const webSocketUrl = 'ws://example.com'; // WebSocket服务器地址
const heartBeatInterval = 5000; // 心跳间隔时间,单位为毫秒let webSocket = null;
let heartBeatTimer = null;function initWebSocket() {webSocket = new WebSocket(webSocketUrl);webSocket.onopen = () => {console.log('WebSocket连接已建立');// 建立连接后开始发送心跳包startHeartBeat();};webSocket.onmessage = (event) => {// 处理服务器发送的消息console.log('收到服务器消息:', event.data);};webSocket.onclose = () => {console.log('WebSocket连接已关闭');// 连接关闭后停止心跳包stopHeartBeat();// 可根据需要重新连接// reconnect();};
}function startHeartBeat() {// 每隔一段时间发送心跳包heartBeatTimer = setInterval(() => {if (webSocket.readyState === WebSocket.OPEN) {webSocket.send('ping'); // 发送心跳包}}, heartBeatInterval);
}function stopHeartBeat() {// 停止心跳包发送clearInterval(heartBeatTimer);
}// 初始化WebSocket连接
initWebSocket();
案例
实现一个简易的聊天功能
1.创建一个文件夹
2.初始化
npm init -y
npm install websocket
3.创建websocket服务端,命名为server.js
const websocket=require("websocket").server
const http=require('http');
const httpServer = http.createServer().listen(8080, ()=>{console.log('cyl: ','http://localhost:8080');
})
const websocketServer = new websocket({httpServer: httpServer,autoAcceptConnections: false
})
const conArr = []
websocketServer.on('request', function(request) {// 这就是一次客户端发送的消息// websocket 需要将这个链接保存起来// 只要客户端和服务器没有断开,这个链接必须在// 客户端与服务端的通信都是从这个链接上通信const connection = request.accept()// 每次接收一个链接,将它存放在数组里面conArr.push(connection)console.log(connection)// 监听客户端发送的消息connection.on('message', function(message) {console.log(message);// 发送消息给客户端(广播到各个客户端)// 后面加上 utf8Data 编码// 要将所有的链接全部发出去,才可以让每个客户端接收到其他传来的数据for(let i = 0; i < conArr.length; i++) {conArr[i].send(message.utf8Data)}})
})
4.创建传送给客户端的文件index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- 需要一进入浏览器就要建立链接 --><!-- 点击按钮发送消息给服务器 -->输入姓名:<input type="text" id="uName"><br>输入消息:<input type="text" id="context"><button id="btn"> 点击发送消息 </button><div id="charRoom"></div><script>// 用户名const uName = document.getElementById('uName')// 文本框内容const context = document.getElementById('context')// 点击按钮const btn = document.getElementById('btn')// 要显示聊天室的区域const charRoom = document.getElementById('charRoom')// 实例化 websocket// 必须加 'ws://localhost:8080' ws 协议,后面是开启的服务端接口const websocket = new WebSocket('ws://localhost:8080')// 打开事件websocket.onopen = function() {// 获取当前链接的状态// 1 是建立了链接console.log(websocket.readyState);}// 点击发送消息的事件btn.onclick = function() {// 将用户名和要发送的内容放在一个对象中,一起传送给后端const values = {uName: uName.value,context: context.value}// 清空文本框的内容uName.value = ''context.value = ''// 通过 websocket发送消息websocket.send(JSON.stringify(values))}// 接收服务器返回的消息websocket.onmessage = function(data) {console.log("服务器返回的数据",data)// 服务器返回过来的聊天信息const chatS = JSON.parse(data.data)// 添加到页面上charRoom.innerHTML += `<strong>${chatS.uName}:</strong><span>${chatS.context}</span><br />`}// 服务器断开连接,客户端会触发websocket.onclose = function() {}</script>
</body>
</html>
4.启动服务端
node server.js
服务启动成功


相关文章:
即时通信的方法和webSocket的具体使用
前言 之前遇到过需要即时通讯的场景,刚开始使用的是通过轮询的方式,定时器3秒向服务器请求一次数据,后面发现如果在手机端长时间打开使用此功能的页面,可能会发生手机发热,甚至卡顿的现象。最后改用webSocket…...
HTML 速查列表
HTML 速查列表 HTML 速查列表. 你可以打印它,以备日常使用。 HTML 基本文档 <!DOCTYPE html> <html> <head> <title>文档标题</title> </head> <body> 可见文本... </body> </html> 基本标签(Ba…...
Hadoop集成Hive
一、环境与软件准备 说明:服务器已用主机名代替,可根据自己的需求,改为IP地址 环境 服务器组件masterNameNode、DataNode、Nodemanager、ResourceManager、Hive、Hive的metastore、Hive的hiveserver2、mysqlSecondarySecondaryNameNode、D…...
MyBatis查询数据库
目录 一、什么是MyBatis 二、搭建MyBatis开发环境 🍅添加MyBatis依赖 🍅在数据库添加数据 🍅设置MyBatis配置 🎈数据库的相关连接信息🎈xml的保存和设置路径 三、使用MyBatis模式和语法操作数据库 ἴ…...
RVM问题记录 - Error running ‘__rvm_make -j10‘
文章目录 前言开发环境问题描述问题分析解决方案最后 前言 公司新到一台电脑需要配置开发环境,在用RVM安装Ruby时遇到了一个奇怪的问题。 开发环境 RVM: 1.29.12OpenSSL: 3.1.1 问题描述 执行命令安装Ruby 3.0版本: rvm install ruby-3.0.0在编译阶…...
VIS for AI :ConvNetJS
1.简单介绍: ConvNetJS是由斯坦福大学计算机科学系的Andrej Karpathy开发的一个深度学习框架,用于在浏览器中运行卷积神经网络(ConvNet)。ConvNetJS可以帮助开发人员在客户端(浏览器)上进行深度学习任务&a…...
【Python入门系列】第二十篇:Python区块链和加密货币
文章目录 前言一、区块链基础知识1.1 什么是区块链1.2 区块链的工作原理 1.3 区块链的优势和应用场景二、Python实现区块链2.1 创建区块类2.2 创建区块链类2.3 添加区块和验证区块链 三、加密货币基础知识3.1 什么是加密货币3.2 加密货币的工作原理3.3 加密货币的挖矿和交易 四…...
MySQL 服务器的调优策略
点击上方↑“追梦 Java”关注,一起追梦! 在工作中,我们发现慢查询一般有2个途径,一个是被动的,一个是主动的。被动的是当业务人员反馈某个查询界面响应的时间特别长,你才去处理。主动的是通过通过分析慢查询…...
Educational Codeforces Round 152 (Rated for Div. 2)
B这个题目在20分钟的时候发现了取模的规律,但是在写法上我竟然犹豫了,这影响了我后面题目的心态 过于可惜了 但是没关系,现在不会,之后就会写了 这里强调一下,sort不会改变原先的顺序,就是说如果两个相等的…...
CSPM难度大吗?对比pmp怎么样?
CSPM证书是刚出来的,难度不会很大,大家都知道 PMP 证书是从国外引进的,近几年很热门,持证人数已经高达 90 余万了,但是目前我们和老美关系大家有目共睹,一直推国际标准和美国标准感觉有点奇怪。 现在新出台…...
Android.mk中的LOCAL_OVERRIDES_PACKAGES用法
Android.mk中的LOCAL_OVERRIDES_PACKAGES用法_mk local_over_觅风者的博客-CSDN博客 Android.mk中的LOCAL_OVERRIDES_PACKAGES的用法说明可以参考以下文章: Android.mk覆盖替换LOCAL_OVERRIDES_PACKAGES 此变量可以使其他的模块不加入编译 项目中遇到的问题&…...
Matlab遍历文件及直方图统计
参考链接: 使用MATLAB遍历文件 strtrim用法 strsplit用法 cell单元数据使用{} close all; dir_path C:/Users/; fileFolder ls(dir_path); fileNum length(fileFolder(:,1)) - 2; for i 3:(3fileNum-1)file_path strcat(dir_path, strtrim(fileFolder(i,:)))…...
为什么要格式化硬盘?硬盘格式化了数据怎么恢复
在计算机维护和数据管理中,格式化硬盘是一个常见的操作。本文将探讨为什么需要对硬盘进行格式化以及当数据丢失时如何恢复。 ▌格式化硬盘是什么意思: 硬盘格式化是对磁盘或其分区进行初始化的一种操作,它会清除磁盘或分区中的所有文件。因此…...
PHP注册、登陆、6套主页-带Thinkphp目录解析-【白嫖项目】
强撸项目系列总目录在000集 PHP要怎么学–【思维导图知识范围】 文章目录 本系列校训本项目使用技术 上效果图主页注册,登陆 phpStudy 设置导数据库项目目录如图:代码部分:控制器前台的首页 其它配套页面展示直接给第二套方案的页面吧第三套…...
antDesignMobile中Switch配合Form使用无效解决方案
介绍 Form和Switch合起来使用无效的原因就是因为Form.Item给Switch的是value值,而Switch中监听的是checked;所以说我们只需要做一层二次封装即可。非常简单~如下本文以antd-mobile举例,其他antd框架解决方案一致!!&am…...
记录springboot在k8s下无法读取文件问题
//加载配置文件 File file ResourceUtils.getFile("classpath:/template/job.yaml"); /对象映射 V1Job v1Job (V1Job) Yaml.load(file); 开发的时候使用上面的方法可以读取文件数据,但是部署到k8s容器中之后,读取文件出现报错,…...
数据湖如何为企业带来9%的高增长?可否取代数据仓库?
什么是数据湖? 数据湖是一个集中的存储库,允许您以任何规模存储所有结构化和非结构化数据。您可以按原样存储数据,而不必首先构造数据,并运行不同类型的分析—从仪表板和可视化到大数据处理、实时分析和机器学习,以指…...
P2669 [NOIP2015 普及组] 金币
题目背景 NOIP2015 普及组 T1 题目描述 国王将金币作为工资,发放给忠诚的骑士。第一天,骑士收到一枚金币;之后两天(第二天和第三天),每天收到两枚金币;之后三天(第四、五、六天&a…...
【2023】华为OD机试真题Java CC++ Python JS Go-题目0250-选修课
题目0250-选修课 题目描述 现有两门选修课,每门选修课都有一部分学生选修,每个学生都有选修课的成绩,需要你找出同时选修了两门选修课的学生,先按照班级进行划分,班级编号小的先输出,每个班级按照两门选修课成绩和的降序排序,成绩相同时按照学生的学号升序排序。 输入…...
lama cleaner
这里写自定义目录标题 安装参数包含的额外plugins 代码结构FreehandBackground RemovalInteractiveSeg 安装 conda create --name lamacleaner python3.10 pip install -r requirements.txt pip install gfpgan pip install realesrgan pip install rembg pip install .如果…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
