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

JavaScript 第23章:WebSocket 与实时通讯

在JavaScript中使用WebSocket进行实时通信是一个非常实用且强大的功能。下面我们将详细介绍WebSocket协议的基础知识、如何使用WebSocket对象以及如何构建一个简单的实时通信应用。

WebSocket 协议

WebSocket是一个在单个TCP连接上进行全双工通信的协议。WebSocket使得数据可以在浏览器和服务器之间双向流动,这对于需要频繁更新或即时通讯的应用来说是一个巨大的进步。传统的HTTP请求是短连接,即客户端请求服务器后,服务器响应并关闭连接;而WebSocket则保持连接开放,允许服务器主动向客户端推送数据。

WebSocket 对象

在JavaScript中,通过WebSocket构造函数可以创建WebSocket对象。这个对象提供了几个关键的方法和事件来处理连接、发送消息以及接收消息。

创建WebSocket对象
var socket = new WebSocket('ws://example.com/socket');

这里的URL前缀是ws:(对于加密连接则是wss:)。

WebSocket 对象的事件
  • open: 当连接建立时触发。
  • message: 当从服务器接收到消息时触发。
  • error: 当发生错误时触发。
  • close: 当连接关闭时触发。
WebSocket 对象的方法
  • send(data): 向服务器发送数据。
  • close(): 关闭连接。

实时通讯应用示例

让我们来看一个简单的实时聊天应用的例子。这里将包括客户端和服务端的部分。

客户端(HTML + JavaScript)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket Chat</title>
<script>var socket = new WebSocket('ws://localhost:8080');socket.onopen = function(e) {console.log("Connection opened");};socket.onmessage = function(event) {var msg = document.createElement('p');msg.innerText = event.data;document.getElementById('messages').appendChild(msg);};socket.onerror = function(error) {console.log('Error:', error);};socket.onclose = function(e) {console.log('Socket closed');};function sendMessage() {var input = document.getElementById('input');socket.send(input.value);input.value = '';}
</script>
</head>
<body>
<div id="messages"></div>
<input type="text" id="input">
<button onclick="sendMessage()">Send</button>
</body>
</html>
服务端(Node.js)

为了简化起见,这里使用Node.js作为服务端实现。实际应用中可能需要更复杂的逻辑来处理多个连接等。

const WebSocket = require('ws');const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', function connection(ws) {ws.on('message', function incoming(message) {console.log('received: %s', message);// 这里可以选择广播给所有连接的客户端wss.clients.forEach(function each(client) {if (client !== ws && client.readyState === WebSocket.OPEN) {client.send(message);}});});ws.on('close', function close() {console.log('Client disconnected');});
});console.log('Server is running on ws://localhost:8080');

这个例子中,客户端会显示来自其他客户端的消息,并允许用户输入并发送信息。服务端则负责接收消息并将消息广播给所有已连接的客户端。

以上就是关于WebSocket的一个基础介绍和简单的应用实例。在实际开发中,可能还需要考虑更多的细节如安全性、错误处理等。

当然,让我们继续深入探讨WebSocket在实际应用中的注意事项和技术细节。

WebSocket 在实际应用中的注意事项

安全性
  • TLS/SSL 加密:使用wss:而不是ws:来确保通信的安全性。
  • 身份验证:确保只有经过认证的用户才能连接到你的WebSocket服务器。
  • 授权:根据用户的权限控制他们可以访问的数据类型。
  • 防止XSS攻击:对从WebSocket接收的数据进行适当的编码处理,避免跨站脚本攻击。
错误处理
  • 断线重连:当连接意外中断时,客户端应该能够自动尝试重新连接。
  • 心跳机制:为了避免因为长时间无活动而导致的连接超时,可以定期发送心跳包来维持连接活跃状态。
性能优化
  • 压缩数据:使用压缩算法减少传输的数据量。
  • 合理设计协议:定义清晰简洁的消息格式可以提高解析速度。
跨域支持
  • CORS:WebSocket同样支持CORS(Cross-Origin Resource Sharing),这意味着服务器可以通过设置适当的头部来允许来自不同源的连接。

更多高级用法

广播消息

在之前的服务端示例中,我们展示了如何向所有连接的客户端广播消息。但在实际应用中,可能需要更加精细的控制,比如仅向特定房间内的用户发送消息。

存储会话状态

WebSocket本身并不保存会话状态,因此需要借助其他技术(如数据库、Redis等)来存储客户端的状态信息。

消息队列

在高并发场景下,直接将消息发送到客户端可能会导致性能瓶颈。使用消息队列(如RabbitMQ、Kafka等)可以帮助管理消息的发送,减轻服务器的压力。

示例:增加心跳检测和自动重连

接下来,我们在之前的客户端示例基础上增加心跳检测和自动重连的功能。

var socket = new WebSocket('ws://localhost:8080');
var heartbeat = null;socket.onopen = function(e) {console.log("Connection opened");heartbeat = setInterval(sendHeartbeat, 5000); // 每5秒发送一次心跳
};socket.onmessage = function(event) {var msg = document.createElement('p');msg.innerText = event.data;document.getElementById('messages').appendChild(msg);// 如果接收到的是心跳消息,则回复心跳if (event.data === 'ping') {socket.send('pong');}
};socket.onerror = function(error) {console.log('Error:', error);reconnect();
};socket.onclose = function(e) {console.log('Socket closed');clearInterval(heartbeat);reconnect();
};function sendHeartbeat() {socket.send('ping');
}function reconnect() {setTimeout(() => {socket = new WebSocket('ws://localhost:8080');}, 5000); // 失败后5秒重试连接
}function sendMessage() {var input = document.getElementById('input');socket.send(input.value);input.value = '';
}

此代码段增加了心跳检测功能,并在连接失败时自动尝试重新连接。服务端也需要相应地添加对心跳的支持。

以上就是有关WebSocket的一些扩展知识点及其在实际项目中的应用技巧。希望这些信息能帮助你在开发中更好地利用WebSocket。

并发连接处理

在WebSocket应用中,随着用户的增加,服务器需要同时处理大量的并发连接。这要求服务器具有良好的可扩展性和资源管理能力。

使用集群和负载均衡
  • Node.js 集群模块:可以使用Node.js内置的cluster模块来创建工作进程,从而利用多核CPU的性能。
  • 负载均衡器:使用外部负载均衡器(如Nginx)来分散请求到不同的WebSocket服务器节点上。
分布式会话管理
  • 共享会话状态:使用Redis或其他分布式缓存解决方案来存储会话状态,确保即使在节点故障的情况下也能恢复会话。

优化WebSocket服务器性能

随着连接数的增长,服务器资源(如内存和CPU)的消耗也会增加。以下是一些性能优化策略:

内存管理
  • 对象池:预先创建和复用WebSocket对象,以减少垃圾回收的压力。
  • 缓存管理:合理使用缓存,减少不必要的数据交换。
CPU使用
  • 非阻塞IO:使用异步非阻塞IO操作,避免阻塞主线程。
  • 事件驱动:采用事件驱动的设计模式,如Node.js的EventEmitter,以减少不必要的计算。

构建复杂应用逻辑

随着应用程序变得越来越复杂,仅仅使用WebSocket可能不足以满足所有的需求。以下是几种扩展WebSocket应用的方式:

用户认证与权限控制
  • JWT(JSON Web Tokens):用于认证用户,提供一种安全的方式来传递信息。
  • OAuth2:适用于需要第三方认证的应用场景。
消息队列与持久化
  • 消息队列:使用如RabbitMQ或Kafka来处理消息的持久化和顺序保证。
  • 数据库集成:将消息记录到数据库中,以备后续分析或恢复使用。
实时通知系统
  • Webhooks:可以用来通知外部系统有新的事件发生。
  • 推送通知:通过WebSocket可以实现实时的推送通知,如邮件提醒、聊天消息等。
实时协作工具
  • 同步编辑:像Google Docs这样的实时文档编辑工具,需要在多个客户端之间同步变化。
  • 在线游戏:实时的游戏数据交换,要求低延迟和高可靠性。

实现示例:用户认证与消息转发

假设我们要构建一个带有用户认证的聊天室应用,用户必须登录后才能发送和接收消息。我们可以使用JWT来进行认证,并在服务端验证每个请求。

服务端实现(Node.js)
const WebSocket = require('ws');
const jwt = require('jsonwebtoken');
const secret = 'your-secret';// 假设有一个数据库模型来获取用户信息
async function getUser(username) {// 返回用户信息或错误
}const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', async function connection(ws, req) {const token = req.headers.authorization;try {const decoded = jwt.verify(token, secret);const user = await getUser(decoded.username);if (!user) throw new Error('Invalid user');// 用户已认证,可以加入聊天室ws.user = user;ws.send(JSON.stringify({ type: 'welcome', message: 'Welcome to the chat!' }));ws.on('message', function incoming(message) {let data = {};try {data = JSON.parse(message);} catch (e) {console.error('Error parsing message:', e);return;}if (data.type === 'chat') {data.user = ws.user.username;wss.clients.forEach(function each(client) {if (client !== ws && client.readyState === WebSocket.OPEN) {client.send(JSON.stringify(data));}});}});} catch (e) {console.error('Authentication failed:', e);ws.close();}ws.on('close', function close() {console.log('User disconnected');});
});console.log('Server is running on ws://localhost:8080');

在这个示例中,我们首先验证了WebSocket连接请求中的JWT令牌。如果验证成功,允许用户加入聊天室,并监听他们的消息。如果接收到的是聊天消息,则将消息转发给所有已连接的客户端。

客户端实现

客户端需要先获取JWT令牌,然后使用该令牌建立WebSocket连接。

let token = 'your-token-here'; // 假设已经获取到了token
var socket = new WebSocket('ws://localhost:8080');socket.onopen = function(e) {console.log("Connection opened");socket.send(JSON.stringify({ type: 'auth', token }));
};socket.onmessage = function(event) {let data = JSON.parse(event.data);switch (data.type) {case 'welcome':console.log(data.message);break;case 'chat':var msg = document.createElement('p');msg.innerText = `${data.user}: ${data.message}`;document.getElementById('messages').appendChild(msg);break;}
};socket.onerror = function(error) {console.log('Error:', error);
};socket.onclose = function(e) {console.log('Socket closed');
};function sendMessage() {var input = document.getElementById('input');socket.send(JSON.stringify({ type: 'chat', message: input.value }));input.value = '';
}

这个客户端示例在连接打开后发送一个认证消息,并监听来自服务器的消息。当接收到聊天消息时,将其展示在页面上。

通过上述方法,您可以构建出更加健壮和安全的WebSocket应用。

相关文章:

JavaScript 第23章:WebSocket 与实时通讯

在JavaScript中使用WebSocket进行实时通信是一个非常实用且强大的功能。下面我们将详细介绍WebSocket协议的基础知识、如何使用WebSocket对象以及如何构建一个简单的实时通信应用。 WebSocket 协议 WebSocket是一个在单个TCP连接上进行全双工通信的协议。WebSocket使得数据可…...

简单汇编教程10 数组

目录 实践&#xff1a;相加连续的数 数组是在内存中连续的一串变量。我这样说&#xff0c;可能你已经想到的大致的定义了&#xff1a; NUMBERS DW 34, 45, 56, 67, 75, 89 现在我们就定义了一个Number数组&#xff0c;里面存放的连续的六个数字&#xff1a;34, 45, 56, …...

Jsoup在Java中:解析京东网站数据

对于电商网站如京东来说&#xff0c;其页面上的数据包含了丰富的商业洞察。对于开发者而言&#xff0c;能够从这些网站中提取有价值的信息&#xff0c;进行分析和应用&#xff0c;无疑是一项重要的技能。本文将介绍如何使用Java中的Jsoup库来解析京东网站的数据。 Jsoup简介 …...

SQL 干货 | SQL 反连接

最强大的 SQL 功能之一是 JOIN 操作&#xff0c;它提供了一种优雅而简单的方法&#xff0c;将一个表中的每一条记录与另一个表中的每一条记录结合起来。不过&#xff0c;有时我们可能想从一个表中找到另一个表中没有的值。正如我们将在今天的博客文章中看到的&#xff0c;通过包…...

JSON 反对序列化 public final class LocalDateTime 日期格式错误

错误日志为&#xff1a; java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of java.time.LocalDateTime (no Creators, like default construct, exist): no String-argument constructor/factory meth…...

Java 集合

1. 集合框架概述 集合框架&#xff08;Collection Framework&#xff09; 是 Java 中为处理一组对象而设计的一套标准化 API&#xff0c;它包括一组通用的接口、实现类和算法。这些接口和类为各种数据结构和操作方法提供了统一的实现方式&#xff0c;使得开发者可以轻松地对数…...

爬虫日常实战

爬取美团新闻信息&#xff0c;此处采用两种方法实现&#xff1a; 注意点&#xff1a;因为此处的数据都是动态数据&#xff0c;所以一定要考虑好向下滑动数据包会更新的情况&#xff0c;不然就只能读取当前页即第一页数据&#xff0c;方法一通过更新ajax数据包网址页数&#xf…...

复写零--双指针

一&#xff1a;题目描述 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 二&#xff1a;算法原理分析 三&#xff1a;代码编写 void duplicateZeros3(vector<int>& arr) {int dest -1, cur 0, n arr.size();//1.找到要复写的最后一个数字while …...

跟着小土堆学习pytorch(二)——TensorBoard和Transform

文章目录 一、TensorBoard1.1 add_scalar()1.1,1 报错&#xff1a;TypeError: MessageToJson() got an unexpected keyword argument including_default_value_fields1.1.2 图像重叠1.1.3 代码展示 1.2 add_image()1.2.1 代码 二、transform2.1 介绍——对图片进行一些变化2.2 …...

自由学习记录(10)

Sprite Packer ~Mode & 图集 packer Project Setting经常是金屋藏娇 创建的项目如果不是2d项目&#xff0c;则默认disable打包 编辑模式就是你没点运行看游戏效果&#xff0c;在狼狈敲码创对象写逻辑的那个状态&#xff0c; 运行模式从点了|>之后&#xff0c;就一直…...

Redis提供了专门的命令来实现自增操作

Redis中的自增操作并不是直接通过CAS&#xff08;Compare and Set&#xff09;操作实现的。Redis提供了专门的命令来实现自增操作&#xff0c;这些命令能够确保操作的原子性&#xff0c;而不需要显式地使用CAS机制。 Redis中的自增操作 Redis中的自增操作主要依赖于以下几个命…...

uniapp修改input中placeholder样式

Uniapp官方提供了两种修改的属性方法&#xff0c;但经过测试&#xff0c;只有 placeholder-class 属性能够生效 <input placeholder"请输入手机验证码" placeholder-class"input-placeholder"/><!-- css --> <style lang"scss" s…...

GenerativeU:生成式开放目标检测

论文&#xff1a;https://arxiv.org/abs/2403.10191 代码&#xff1a;https://github.com/FoundationVision/GenerateU 感想 目标检测任务已经逐渐从闭集场景专项开集场景&#xff0c;在LLM加持下&#xff0c;速读越来越快。该方法仍然依赖于预先定义的类别&#xff0c;这意味着…...

element plus e-table表格中使用多选,当翻页时已选中的数据丢失

摘要&#xff1a; 点击第一页选中两个&#xff0c;再选择第二页&#xff0c;选中&#xff0c;回到第一页&#xff0c;之前选中的要保留&#xff01; element ui table 解决办法&#xff1a; :row-key“getRowKeys” &#xff08;写在el-table中&#xff09; methods中声明 ge…...

CentOS 7 网络连接显示“以太网(ens33)不可用”

1.创建linux虚拟机&#xff0c;配置网络和主机名显示" 以太网&#xff08;ens33&#xff0c;被拔出&#xff09;" 2.桌面右键此电脑&#xff0c;管理&#xff0c;找到“服务和应用程序”&#xff0c;点击“服务”&#xff0c;找到下图两个服务&#xff0c;点击圈起来…...

qt QNetworkProxy详解

一、概述 QNetworkProxy通过设置代理类型、主机、端口和认证信息&#xff0c;可以使应用程序的所有网络请求通过代理服务器进行。它支持为Qt网络类&#xff08;如QAbstractSocket、QTcpSocket、QUdpSocket、QTcpServer、QNetworkAccessManager等&#xff09;配置网络层代理支持…...

推荐IDE中实用AI编程插件,目前无限次使用

插件介绍 一款字节跳动推出的“基于豆包大模型的智能开发工具” 以vscode介绍【pycharm等都可以啊】&#xff0c;这个插件提供智能补全、智能预测、智能问答等能力&#xff0c;节省开发时间 直接在IDE中使用&#xff0c;就不用在网页中来回切换了 感觉还可以&#xff0c;响应速…...

【华为HCIP实战课程十五】OSPF的环路避免及虚链路,网络工程师

一、避免域间路由环路 1、区域内部的防环:区域内同步了LSA,SPF就决定了区域内部没有环路 2、区间的防环机制:非正常的ABR不更新3类LSA 为防止区域间的环路OSPF定义了骨干区域和非骨干区域和三类LSA的传递规则 1)、OSPF划分了骨干区域和非骨干区域,所有非骨干区域均直接…...

【编程语言】正则表达式:POSIX 与 PCRE 的全面比较及应用

目录 正则表达式&#xff1a;POSIX 与 PCRE 的全面比较及应用1. 正则表达式的基本概念1.1 基本元素1.2 正则表达式的历史 2. POSIX 正则表达式2.1 POSIX 正则表达式的语法2.1.1 基本正则表达式 (BRE)2.1.2 扩展正则表达式 (ERE) 2.2 POSIX 正则表达式的使用场景2.3 使用 POSIX …...

Spark Streaming 数据流处理

一、创建Spark Streaming 环境 二、读取数据&#xff08;监听端口&#xff09; 三、任务处理 四、启动程序 我这里写的是简单的单词数量统计 import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream} import org.apache.spark.{SparkConf, SparkConte…...

高效规划神器 markmap:一键将 Markdown 变思维导图!

❤️ 如果你也关注大模型与 AI 的发展现状&#xff0c;且对大模型应用开发非常感兴趣&#xff0c;我会快速跟你分享最新的感兴趣的 AI 应用和热点信息&#xff0c;也会不定期分享自己的想法和开源实例&#xff0c;欢迎关注我哦&#xff01; 微信公众号&#xff5c;搜一搜&…...

微服务基础架构(图)

微服务基础架构是一种现代化的软件架构模式&#xff0c;旨在将大型复杂的应用程序拆分为多个小型、独立的服务。每个微服务专注于特定的业务功能&#xff0c;可独立开发、部署和扩展。 在微服务基础架构中&#xff0c;通常会使用轻量级的通信机制&#xff0c;如 RESTful API 或…...

中电金信:大模型时代 金融机构企业架构转型如何更智能化?

随着人工智能技术的不断进步&#xff0c;AI大模型在金融行业已经广泛应用&#xff0c;推动金融机构实现更高效、智能化的服务&#xff0c;同时也为金融科技领域的发展带来新的挑战。中电金信基于业务建模的企业架构转型解决方案也顺势而动&#xff0c;关注大模型在具体场景上的…...

基于CRNN模型的多位数字序列识别的应用【代码+数据集+python环境+GUI系统】

基于CRNN模型的多位数字序列识别的应用【代码数据集python环境GUI系统】 基于CRNN模型的多位数字序列识别的应用【代码数据集python环境GUI系统】 背景意义 多位手写数字识别&#xff0c;即计算机从纸张文档、照片、触摸屏等来源接收并解释可理解的手写数字输入的能力。 随着…...

windows中命令行批处理脚本学习

目录 一 基础知识二 常见命令1. 输出 echo2. 注释 rem .... %...% :: goto if (10) ()3. 变量 set4. 获取参数 %数字 %*5. 退出 exit6. 复制 copy7.读取输出文件内容 type8. 帮助 命令xxx /?9.等待当前命令运行结束后,才执行下一条命令 call10. 修改字体编码 chcp11. 特殊变量…...

版本工具报错:Error Unity Version Control

NotConfiguredClientException: Unity VCS client is not correctly configured for the current user:Client config file....

ECharts饼图-饼图标签对齐,附视频讲解与代码下载

一、图表效果预览 引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我将带大家一起实现一个饼图图表&#xff0c;通过该图表我们可以直观地展示和分析数据。此外&#…...

Python实现基于WebSocket的stomp协议调试助手工具分享

stomp协议很简单&#xff0c;但是搜遍网络竟没找到一款合适的客户端工具。大多数提供的都是客户端库的使用。可能是太简单了吧&#xff01;可是即便这样&#xff0c;假如有一可视化的工具&#xff0c;将方便的对stomp协议进行抓包调试。网上类似MQTT的客户端工具有很多&#xf…...

《语音识别方案选型研究》

《语音识别方案选型研究》 一、引言二、语音识别技术概述&#xff08;一&#xff09;语音识别的基本原理&#xff08;二&#xff09;语音识别技术的发展历程 三、语音识别方案的分类&#xff08;一&#xff09;基于云端的语音识别方案&#xff08;二&#xff09;基于本地的语音…...

解决关于HTML+JS + Servlet 实现前后端请求Session不一致的问题

1、前后端不分离情况 在处理session过程中&#xff0c;如果前后端项目在一个容器中&#xff0c;session是可以被获取的。例如如下项目结构&#xff1a; 结构 后端的代码是基本的设置值、获取值、销毁值的内容&#xff1a; 运行结果 由此可见&#xff0c;在前后统一的项目中&a…...