在nodejs中实现实时通信的几种方式
在nodejs中实现实时通信的几种方式
在当今世界中,实时通信至关重要。无论是聊天应用程序还是实时体育更新,实时通信都是保持用户活跃度所必需的。Node.js
因其速度、可扩展性和可靠性而成为开发实时应用程序的流行工具。在本文中,我们将探讨为什么 Node.js
是实时通信的理想选择以及如何实现它。
为什么使用 Node.js 进行实时通信?
Node.js
构建在 Google
的 V8 JavaScript
引擎之上,该引擎以其高性能而闻名。这使得 Node.js
成为构建需要速度和可扩展性的实时通信应用程序的完美工具。Node.js
也是事件驱动的,这意味着它可以同时处理多个连接,非常适合构建实时应用程序。
协议和库的类型
Node.js
提供了多种方式来实现实时数据通信。Node.js
中实时数据通信的一些流行库是:
socket.io
socket.io
是一个流行的实时通信库。它使用 WebSockets
作为传输层来提供客户端和服务器之间的实时通信。socket.io
提供了许多功能,例如自动重新连接、对二进制数据的支持以及不支持 WebSocket
的环境的回退选项。
示例代码
服务器端代码:
const express = require('express');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);io.on('connection', (socket) => {console.log('User connected');socket.on('chat:message', (data) => {io.emit('chat:message', data);});socket.on('disconnect', () => {console.log('User disconnected');});
});const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {console.log(`Server listening on port ${PORT}`);
});
客户端代码:
<!DOCTYPE html>
<html>
<head><title>Socket.IO Chat</title>
</head>
<body><div id="messages"></div><form id="chat-form"><input type="text" id="message-input"><button type="submit">Send</button></form><script src="/socket.io/socket.io.js"></script><script>const socket = io();const messagesDiv = document.getElementById('messages');const chatForm = document.getElementById('chat-form');const messageInput = document.getElementById('message-input');chatForm.addEventListener('submit', (event) => {event.preventDefault();const message = messageInput.value.trim();if (message) {socket.emit('chat:message', message);messageInput.value = '';}});socket.on('chat:message', (data) => {const messageDiv = document.createElement('div');messageDiv.innerText = data;messagesDiv.appendChild(messageDiv);});</script>
</body>
</html>
WebSockets
WebSockets
是一种支持客户端和服务器之间实时通信的协议。它通过单个 TCP
连接提供全双工通信通道,允许客户端和服务器之间进行实时数据交换。ws
模块可用于实现 WebSockets
。
示例代码
服务器端代码:
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 3000 });server.on('connection', (socket) => {console.log('User connected');socket.on('message', (message) => {server.clients.forEach((client) => {if (client.readyState === WebSocket.OPEN) {client.send(message);}});});socket.on('close', () => {console.log('User disconnected');});
});
客户端代码:
<!DOCTYPE html>
<html>
<head><title>WebSockets Chat</title>
</head>
<body><div id="messages"></div><form id="chat-form"><input type="text" id="message-input"><button type="submit">Send</button></form>
<script>const socket = new WebSocket('ws://localhost:3000');const messagesDiv = document.getElementById('messages');const chatForm = document.getElementById('chat-form');const messageInput = document.getElementById('message-input');chatForm.addEventListener('submit', (event) => {event.preventDefault();const message = messageInput.value.trim();if (message) {socket.send(message);messageInput.value = '';}});socket.addEventListener('message', (event) => {const messageDiv = document.createElement('div');messageDiv.innerText = event.data;messagesDiv.appendChild(messageDiv);});</script>
</body>
</html>
服务器发送事件
服务器发送事件是一个简单的协议,允许服务器通过 HTTP
连接向客户端发送事件。它非常适合需要单向通信的应用程序,例如现场体育赛事比分或股票市场更新。该模块称为sse
,可用于实现服务器发送事件。
示例代码
服务器端代码:
const express = require('express');
const app = express();app.get('/events', (req, res) => {res.writeHead(200, {'Content-Type': 'text/event-stream','Cache-Control': 'no-cache','Connection': 'keep-alive'});const interval = setInterval(() => {res.write(`data: ${new Date().toLocaleTimeString()}\n\n`);}, 1000);req.on('close', () => {clearInterval(interval);res.end();});
});const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {console.log(`Server listening on port ${PORT}`);
});
客户端代码:
<!DOCTYPE html>
<html>
<head><title>Server-Sent Events Clock</title>
</head>
<body><div id="clock"></div>
<script>const source = new EventSource('/events');const clockDiv = document.getElementById('clock');source.addEventListener('message', (event) => {clockDiv.innerText = event.data;});</script>
</body>
</html>
WebRTC
WebRTC
是一种实时通信协议,允许浏览器建立点对点连接。它在客户端之间提供低延迟的通信通道,而无需服务器。wrtc
库可用于实现 WebRTC
。
示例代码
服务器端代码:
const express = require('express');
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
const { RTCPeerConnection, RTCSessionDescription, RTCIceCandidate } = require('wrtc');
app.use(express.static('public'));io.on('connection', socket => {console.log('Client connected:', socket.id);let pc = new RTCPeerConnection();socket.on('offer', offer => {console.log('Received offer');pc.setRemoteDescription(new RTCSessionDescription(offer)).then(() => {return navigator.mediaDevices.getUserMedia({ audio: true, video: true });}).then(stream => {console.log('Got local stream');stream.getTracks().forEach(track => {pc.addTrack(track, stream);});pc.onicecandidate = event => {if (event.candidate) {socket.emit('candidate', event.candidate);}};pc.ontrack = event => {console.log('Received remote stream');socket.emit('answer', pc.localDescription);};pc.createAnswer().then(answer => {return pc.setLocalDescription(answer);}).catch(error => {console.log('Error creating answer:', error);});}).catch(error => {console.log('Error getting user media:', error);});});socket.on('disconnect', () => {console.log('Client disconnected:', socket.id);pc.close();});
});const PORT = process.env.PORT || 3000;
http.listen(PORT, () => {console.log(`Server listening on port ${PORT}`);
});
客户端代码:
<html><head><meta charset="UTF-8"><title>WebRTC Example</title></head><body><h1>WebRTC Example</h1><div><video id="localVideo" autoplay></video><video id="remoteVideo" autoplay></video></div><div><button id="callButton">Call</button><button id="hangupButton" disabled>Hang Up</button></div><script src="/socket.io/socket.io.js"></script><script>const socket = io.connect('http://localhost:3000');const localVideo = document.getElementById('localVideo');const remoteVideo = document.getElementById('remoteVideo');const callButton = document.getElementById('callButton');const hangupButton = document.getElementById('hangupButton');let pc = new RTCPeerConnection();hangupButton.disabled = true;callButton.onclick = () => {console.log('Calling');navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(stream => {console.log('Got local stream');localVideo.srcObject = stream;stream.getTracks().forEach(track => {pc.addTrack(track, stream);});pc.onicecandidate = event => {if (event.candidate) {socket.emit('candidate', event.candidate);}};pc.ontrack = event => {console.log('Received remote stream');remoteVideo.srcObject = event.streams[0];};pc.createOffer().then(offer => {return pc.setLocalDescription(offer);}).then(() => {socket.emit('offer', pc.localDescription);}).catch(error => {console.log('Error creating offer:', error);});hangupButton.disabled = false;hangupButton.onclick = () => {console.log('Hanging up');pc.close();remoteVideo.srcObject = null;hangupButton.disabled = true;callButton.disabled = false;};}).catch(error => {console.log('Error getting user media:', error);});};socket.on('answer', answer => {console.log('Received answer');pc.setRemoteDescription(new RTCSessionDescription(answer)).catch(error => {console.log('Error setting remote description:', error);});});socket.on('candidate', candidate => {console.log('Received candidate');pc.addIceCandidate(new RTCIceCandidate(candidate)).catch(error => {console.log('Error adding ice candidate:', error);});});</script></body>
</html>
MQTT
mqtt
是一种轻量级消息传递协议,非常适合 IoT
应用程序。它为客户端和服务器之间的通信提供了发布/订阅模型。该模块称为mqtt
,可用于实现 mqtt
。
示例代码
发布者端代码:
const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://test.mosquitto.org');client.on('connect', () => {console.log('connected to MQTT broker');setInterval(() => {client.publish('test', 'Hello MQTT');}, 1000);
});client.on('error', (error) => {console.log(error);
});
订阅者端代码:
const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://test.mosquitto.org');client.on('connect', () => {console.log('connected to MQTT broker');client.subscribe('test', (error) => {if (error) {console.log(error);}});
});client.on('message', (topic, message) => {console.log(`${topic}: ${message}`);
});client.on('error', (error) => {console.log(error);
});
如何确保这种通信的安全
安全性对于任何实时通信应用程序都是至关重要的。可以使用crypto
模块,用于保护客户端和服务器之间的通信。该模块提供加密和解密功能,使得在客户端和服务器之间发送加密消息成为可能。
此外,每种类型都有模块,例如,在 WebSocket
中,有ws
模块,安全的方法是用https
而不是http
包装它。
结论
Node.js
因其速度、可扩展性和可靠性而成为构建实时通信应用程序的绝佳选择。其事件驱动架构使得同时处理多个连接成为可能,并且V8 JavaScript
引擎的使用确保了高性能能力。在 socket.io
等库的帮助下,使用 Node.js
构建实时通信应用程序非常简单。
然而,在处理实时通信应用程序时,安全性至关重要,并且必须使用加密来保护客户端和服务器之间的通信。
还提供了实现实时数据通信的各种方法,每种方法都有自己的一组功能和优点。选择正确的方法取决于您的应用程序的具体要求。socket.io
和 WebSockets
是最流行的实时通信方法,而服务器发送事件、WebRTC
和 MQTT
适用于特定用例。
总体而言,Node.js
是构建实时通信应用程序的强大工具,对于任何需要实时通信的项目都值得考虑。
相关文章:

在nodejs中实现实时通信的几种方式
在nodejs中实现实时通信的几种方式 在当今世界中,实时通信至关重要。无论是聊天应用程序还是实时体育更新,实时通信都是保持用户活跃度所必需的。Node.js 因其速度、可扩展性和可靠性而成为开发实时应用程序的流行工具。在本文中,我们将探讨…...

【tg】 7 GroupInstanceCustomImpl
group GroupInstanceCustomImpl 核心GroupInstanceCustomInternal G:\CDN\P2P-DEV\tdesktop-offical\Telegram\ThirdParty\tgcalls\tgcalls\group\GroupInstanceCustomImpl.h 最核心是是GroupInstanceCustomInternal: private:std::shared_ptr<Threads> _threads;std::u…...

kubernates 集群实战-安装K3s集群
安装K3s集群 安装K3s集群环境准备安装 docker主节点安装work 节点验证环境 安装K3s集群 K3S是一种轻量级的Kubernetes发行版,安装和运行只需要一个二进制文件。相比之下,K8S需要更多的步骤和资源来安装和部署,例如设置etcd集群、安装控制平面…...

通俗介绍:什么是 Redis ?
刚接触 Redis 的伙伴们可能会因为不熟悉而感到困惑。本文简述 Redis 是什么、有哪些作用的问题,是一篇短浅而入门级别的文章。 Redis官网:Redis 打开 Redis 官网可以看到,官方对 Redis 的介绍是这样的:The open source, in-memo…...

蓝桥算法赛(摆玩具)
问题描述 小蓝是一个热爱收集玩具的小伙子,他拥有 n 个不同的玩具。 这天,他把 n 个玩具按照高度顺序从矮到高摆放在了窗台上,然后,他希望将这些玩具分成 k 个段,使得所有分段的极差之和尽可能小。 具体来说&…...

vueDay04——v-if else show
一、v-if的使用 我们可以像c语言一样去使用v-if结构 比如单用v-if,连用v-if v-else,或者是v-if v-else-if v-else 注意: 1.v-if v-else-if需要绑定值,而v-else不需要绑定值 2.if结构可以用在不同的标签类型之间 <div v-if"fir…...

大数据技术学习笔记(二)—— Hadoop 运行环境的搭建
目录 1 准备模版虚拟机hadoop1001.1 修改主机名1.2 修改hosts文件1.3 修改IP地址1.3.1 查看网络IP和网关1.3.2 修改IP地址 1.4 关闭防火墙1.5 创建普通用户1.6 创建所需目录1.7 卸载虚拟机自带的open JDK1.8 重启虚拟机 2 克隆虚拟机3 在hadoop101上安装JDK3.1 传输安装包并解压…...

leetcode系列(双语)002——GO两数相加
文章目录 两数相加 | Add Two Numbers示例个人解答官方解答扩展Algorithm 两数相加 | Add Two Numbers You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a sing…...

废柴勇士(据说没有人能坚持37秒)
欢迎来到程序小院 废柴勇士 玩法:点击屏幕下方左右按键击杀怪物,怪物会在左右方向同时来袭,快速点击按钮进行击杀怪物,看您能够坚持多少秒, 据说还没有能够坚持37秒,快去击杀怪物挑战吧^^。开始游戏https:…...

buuctf_练[羊城杯2020]easyphp
[羊城杯2020]easyphp 文章目录 [羊城杯2020]easyphp掌握知识解题思路关键paylaod 掌握知识 .htaccess文件的利用,把自己指定当做 php文件处理;preg_match正则匹配的了解,stristr函数的绕过;file_put_contents文件写入操作的了…...

【Linux】安装配置虚拟机及虚拟机操作系统的安装
目录 一、操作系统 1. 介绍 2. 功能 3. 有哪些 4. 个人版本和服务器版本的区别 二、VMWare虚拟机 1. 安装 2. 配置 三、安装配置Windows Server 1. 配置 2. 安装 四、虚拟机的环境配置及连接 1. 主机连接虚拟机 2. 虚拟机环境配置及共享 3. 环境配置 一、操作系…...

hugo-stack for github
静态博客框架jekyll、hexo和hugo三者之间的区别与差异 博客生成器? 全名为静态网站生成器, 可在任意拥有主机功能的环境下寄存(托管)可直接配合域名进行全球访问 劣势: 每次更新网页必须重新生成整个网站编译速度(单位:秒) Jek…...

【uniapp】proxy 代理切换至线上测试地址调试接口
本地测试地址形如:http://192.168.124.x:xxxx 线上测试地址形如:https://xxxx.xxxx.com 使用线上地址之后需要修改配置项 secure 为 true const constant require(./src/utils/constant) module.exports {devServer: {proxy: {/api: {target: constan…...

对比Vue2和Vue3的自定义指令
一、自定义指令简介 自定义指令是Vue提供的能力,用于注册自定义的指令,从而实现一些自定义的DOM操作。 二、Vue2中自定义指令 在Vue2中,自定义指令通过全局方法Vue.directive()进行注册: // 注册全局指令v-focus Vue.directive(focus, {inserted: function(el) {el.focus()…...

Python:实现日历到excel文档
背景 日历是一种常见的工具,用于记录事件和显示日期。在编程中,可以使用Python编码来制作日历。 Python提供了一些内置的模块和函数,使得制作日历变得更加简单。 在本文,我们将探讨如何使用Python制作日历,并将日历输出到excel文档中。 效果展示 实现 在代码中会用到cale…...

C++ 异常和错误处理机制:如何使您的程序更加稳定和可靠
在C编程中,异常处理和错误处理机制是非常重要的。它们可以帮助程序员有效地处理运行时错误和异常情况。本文将介绍C中的异常处理和错误处理机制。 什么是异常处理? 异常处理是指在程序执行过程中发生异常或错误时,程序能够捕获并处理这些异常…...

第1章 Java、IDEA环境部署与配置
JavaEE简介与IDE环境部署 课程目录 JavaEE简介JDK环境部署IntelliJ IDEA环境部署 JavaEE简介 1. JavaEE是什么? Java EE(Java Platform,Enterprise Edition)是sun公司(2009年4月20日甲骨文将其收购)推…...

如何进行二进制文件的读写操作?
在C语言中,进行二进制文件的读写操作是非常常见的任务,尤其在处理文件、图像、音频和视频等二进制数据时。本文将详细介绍如何进行二进制文件的读写操作,包括如何打开文件、读取文件、写入文件以及关闭文件。我们将使用标准C库中的函数来执行…...

python实现PDF表格与文本分别导出EXCEL
现需将pdf 转换至Excel , 目前实现方式:将PDF的TABLE部分与 非 TABLE部分分别导出至Excel两个sheet中 1)、识别PDF中的表格块 2)、将PDF转换为Word格式 3)、提取Word中非表格的文本数据 4)、对文本与表格重…...

Java开发-WebSocket
WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信-浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并实现 双向数据传输。 使用 导入maven坐标 <dependency><groupId>org.springframework.bo…...

SpringDoc API文档工具集成SpringBoot - Swagger3
1、引言 之前在Spring Boot项目中一直使用的是SpringFox提供的Swagger库,发现已经超过3年没出新版本了!SpringDoc是一款可以结合Spring Boot使用的API文档生成工具,基于OpenAPI 3,是一款更好用的Swagger库!值得一提的是…...

Java将djvu文件转成pdf
需求来源 迫于有部分资源是djvu格式的文件,需要预览这部分文件,web端无法直接预览djvu,所以需要将djvu转成pdf。 转换方法 简单来说就是先把djvu文件转换成tiff文件,再将tiff文件转换成pdf文件。 Ubuntu服务器 如果服务器是U…...

【机器学习合集】激活函数合集 ->(个人学习记录笔记)
文章目录 综述1. S激活函数(sigmoid&Tanh)2. ReLU激活函数3. ReLU激活函数的改进4. 近似ReLU激活函数5. Maxout激活函数6. 自动搜索的激活函数Swish 综述 这些都是神经网络中常用的激活函数,它们在非线性变换方面有不同的特点。以下是这些激活函数的主要区别&am…...

【从0到1设计一个网关】什么是网关?以及为什么需要自研网关?
文章目录 什么是网关?网关类型网关的优缺点目前的网关解决方案有哪些?为什么要自研Gateway网关?自研网关需要注意什么? 注: 这篇文章作为我的网关的第一篇文章,并不涉及任何代码,只是提及了网关…...

Tp框架如何使用事务和锁,还有查询缓存
1.事务 在ThinkPHP框架中,可以使用think\db\Transaction类来实现事务。 use think\Db; use think\db\Transaction;// 开始事务 Db::startTrans();try {// 执行数据库操作Db::table(user)->where(id, 1)->update([name > John]);// 提交事务Db::commit(); }…...

Java IDEA feign调用上传文件MultipartFile以及实体对象亲测可行
Java IDEA feign调用上传文件MultipartFile以及实体对象亲测可行 1. 报错 java.lang.IllegalStateException: Body parameter cannot be used with form parameters2. 解决参考 1. 报错 java.lang.IllegalStateException: Body parameter cannot be used with form parameters …...

【产品经理】APP备案(阿里云)
工信部《关于开展移动互联网应用程序备案工作的通知》 工业和信息化部印发了《关于开展移动互联网应用程序备案工作的通知》,“在中华人民共和国境内从事互联网信息服务的App主办者,应当依照相关法律法规等规定履行备案手续,未履行备案手续的…...

Overmind VS Redux
Overmind Overmind 是一个状态管理库,它可以帮助你管理应用程序的状态和副作用。下面是一个使用 Overmind 的简单示例: 首先,我们需要安装 Overmind 和它的 React 绑定: npm install overmind overmind-react然后,我…...

0基础学习PyFlink——流批模式在主键上的对比
假如我们将《0基础学习PyFlink——使用PyFlink的Sink将结果输出到外部系统》中的模式从批处理(batch)改成流处理(stream),则其在print连接器上产生的输出是不一样。 批处理 env_settings EnvironmentSettings \.new_…...

Java学习笔记(五)——数组、排序和查找
一、数组 (一)数组的使用 1、使用方式1——动态初始化 2、使用方式2——动态初始化 3、使用方式3——静态初始化 (二)数组使用注意事项和细节 (三)数组赋值机制 (四)数组拷贝…...