在nodejs中实现实时通信的几种方式

news2024/9/28 19:18:40

在nodejs中实现实时通信的几种方式

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

为什么使用 Node.js 进行实时通信?

Node.js 构建在 GoogleV8 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.ioWebSockets 是最流行的实时通信方法,而服务器发送事件、WebRTCMQTT 适用于特定用例。

总体而言,Node.js 是构建实时通信应用程序的强大工具,对于任何需要实时通信的项目都值得考虑。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【学习笔记】记录一个win 11 操作文件卡顿,Windows 资源管理器CPU占用飙升问题

【学习笔记】记录一个win 11 操作文件卡顿&#xff0c;Windows 资源管理器CPU占用飙升问题 前段时间忽然发现电脑操作文件都会特别的卡&#xff0c;例如复制粘贴文件&#xff0c;写入文件等操作&#xff0c;卡的怀疑人生&#xff0c;原本以为是电脑太久没重启&#xff0c;重启…

如何将本地 PDF 文件进行翻译

在日常工作和学习中&#xff0c;我们经常会遇到需要翻译 PDF 文件的情况。比如&#xff0c;我们需要将一份英文的技术文档翻译成中文&#xff0c;或者将一份中文的法律文件翻译成英文。 传统上&#xff0c;我们可以使用专业翻译软件或服务来翻译 PDF 文件。但是&#xff0c;这…

【产品经理】APP备案(阿里云)

工信部《关于开展移动互联网应用程序备案工作的通知》 工业和信息化部印发了《关于开展移动互联网应用程序备案工作的通知》&#xff0c;“在中华人民共和国境内从事互联网信息服务的App主办者&#xff0c;应当依照相关法律法规等规定履行备案手续&#xff0c;未履行备案手续的…

Linux shell编程学习笔记15:定义数组、获取数组元素值和长度

一、 Linux shell 脚本编程中的数组概述 数组是一种常见的数据结构。跟大多数编程语言一样&#xff0c;大多数Linux shell脚本支持数组&#xff0c;但对数组的支持程度各不相同&#xff0c;比如数组的维度&#xff0c;是支持一维数组还是多维数组&#xff1f;再如&#xff0c;…

MongoDB 的集群架构与设计

一、前言 MongoDB 有三种集群架构模式&#xff0c;分别为主从复制&#xff08;Master-Slaver&#xff09;、副本集&#xff08;Replica Set&#xff09;和分片&#xff08;Sharding&#xff09;模式。 Master-Slaver 是一种主从复制的模式&#xff0c;目前已经不推荐使用。Re…

threejs(3)-详解材质与纹理

一、Matcap(MeshMatcapMaterial)材质原理与应用 Matcap是一张含有光照信息的贴图&#xff0c;通常是直接截取材质球截图来使用。因此Matcap可以很好的模拟静止光源下的光照效果。 最直接的方式就是直接使用在View空间下的模型法向量的xy分量去采样Matcap。 另外还有一种常见…

STM32F103单片机内部RTC实时时钟驱动程序

一、STM32f103系列RTC功能 RTC实时时钟功能是嵌入式软件开发中比较常用的功能&#xff0c;一般MCU的RTC功能都带有年月日时间寄存器&#xff0c;比如STM32F4xx系列&#xff0c;RTC描述如下&#xff1a; 可见F4系列的RTC功能比较强大&#xff0c;设置好初始时间后&#xff0c;读…

Power BI 傻瓜入门 8. 制作数据模型

本章内容包含&#xff1a; 描述不同的数据建模技术配置属性以满足数据模型要求设计模型以满足性能要求 您可能认为&#xff0c;通过Power BI对数据进行转换后&#xff0c;您将一帆风顺。在某些情况下&#xff0c;这是正确的。当然&#xff0c;当您创建了一个包含许多表的详细…

OpenCV 笔记(3):基本图形的绘制

Part11. 绘制简单的图形 绘图功能是 OpenCV 最基础的功能&#xff0c;OpenCV 提供了基础的绘制函数&#xff0c;用于帮助我们绘制一些基本的图形。通过这些函数的组合&#xff0c;我们也可以做一些高级的应用。 11.1 绘制点和圆 OpenCV 的绘制函数相对简单&#xff0c;而且很多…

[Unity]将所有 TGA、TIFF、PSD 和 BMP(可自定义)纹理转换为 PNG,以减小项目大小,而不会在 Unity 中造成任何质量损失

如何使用 只需在“项目”窗口中创建一个名为“编辑器”的文件夹&#xff0c;然后在其中添加此脚本即可。然后&#xff0c;打开窗口-Convert Textures to PNG&#xff0c;配置参数并点击“Convert to PNG&#xff01; ”。 就我而言&#xff0c;它已将某些 3D 资源的总文件大小…

C语言汇总

汇总一&#xff08;linux环境&#xff09; /bin &#xff1a;bin是二进制&#xff08;binary&#xff09;英文缩写。 /boot&#xff1a;存放的都是系统启动时要用到的程序。 /dev&#xff1a;包含了所有Linux系统中使用的外部设备。 /etc&#xff1a;存放了系统管理时要用到的…

uniapp中 background-image 设置背景图片不展示问题

有问题 <view class"file-picker__box jsz" tap"jszxszUpload(jsz)"></view>.jsz {background-image: url(../../static/example_drive.png); }解决1 <view class"file-picker__box jsz" :style"{ background-image: url(…

Android APP 隐藏系统软键盘的方法

1.场景描述&#xff1a; 1) APP项目中经常会开发自定义软键盘&#xff1b;同时在使用EditText时&#xff0c;也会常常遇到自动弹出系统自带的软键盘&#xff0c;与自定义的软键盘产生冲突的情况&#xff1b;此时需要禁止EditText自动弹出系统软键盘&#xff0c;从而使自定义的…

汽车电子专有名词与相应技术

1.EEA &#xff08;Electronic & Electrical Architecture 电子电气架构&#xff09; EEA在宏观上概括为物理架构与逻辑架构的结合&#xff0c;微观上通过众多电子元器件的协同配合&#xff0c;或集成式或分布式的系统级电子电气架构&#xff0c;具体详见专栏 新能源汽车电…

volatile 关键字有什么用?它的实现原理是什么?

volatile volatile是Java中的一个关键字&#xff0c;用于修饰变量&#xff0c;表示该变量是“易变的”&#xff08;Volatile&#xff09;。 volatile 关键字有两个作用&#xff1a; 可以保证在多线程环境下共享变量的可见性。 通过增加内存屏障防止多个指令之间的重排序。 可见…

【图结构从入门到应用】图的表示和遍历,图搜索算法详解与示例

1图的概念 图是一种非常常见的数据结构&#xff0c;用于表示对象之间的关系。在计算机科学中&#xff0c;有许多不同的图类型&#xff0c;包括有向图&#xff08;Directed Graph&#xff09;和无向图&#xff08;Undirected Graph&#xff09;。图通常由节点&#xff08;顶点&a…

vscode json文件添加注释报错

在vscode中创建json文件&#xff0c;想要注释一波时&#xff0c;发现报了个错&#xff1a;Comments are not permitted in JSON. (521)&#xff0c;意思是JSON中不允许注释 以下为解决方法&#xff1a; 在vscode的右下角中找到这个&#xff0c;点击 在出现的弹窗中输入json wit…

Python 自动化(十五)请求和响应

准备工作 将不同day下的代码分目录管理&#xff0c;方便后续复习查阅 (testenv) [rootlocalhost projects]# ls mysite1 (testenv) [rootlocalhost projects]# mkdir day01 day02 (testenv) [rootlocalhost projects]# cp -rf mysite1/ day01/ (testenv) [rootlocalhost proj…

vue路径中“@/“代表什么

举例&#xff1a; <img src"/../static/imgNew/adv/tupian.jpg"/>其中&#xff0c;/是webpack设置的路径别名&#xff0c;代表什么路径&#xff0c;要看webpack的build文件夹下webpack.base.conf.js里面对于是如何配置&#xff1a; 上图中代表src,上述代码就…

KDChart3.0编译过程-使用QT5.15及QT6.x编译

文章目录 参考原文一、下载KDChart源文件二、下载安装CMake三、编译Qt5.15.0 编译Qt6.x 编译使用Qt6.X编译的直接看这最快 四、使用测试方法一&#xff1a;测试方法二&#xff1a; 参考原文 记录我的KDChart3.0编译过程 系统&#xff1a;win11&#xff0c;Qt5.15 &#xff0c;编…