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


    在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}`);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    客户端代码:

    DOCTYPE html>
    <html>
    <head>
      <title>Socket.IO Chattitle>
    head>
    <body>
      <div id="messages">div>
      <form id="chat-form">
        <input type="text" id="message-input">
        <button type="submit">Sendbutton>
      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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    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');
      });
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    客户端代码:

    DOCTYPE html>
    <html>
    <head>
      <title>WebSockets Chattitle>
    head>
    <body>
      <div id="messages">div>
      <form id="chat-form">
        <input type="text" id="message-input">
        <button type="submit">Sendbutton>
      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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    服务器发送事件

    服务器发送事件是一个简单的协议,允许服务器通过 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}`);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    客户端代码:

    DOCTYPE html>
    <html>
    <head>
      <title>Server-Sent Events Clocktitle>
    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    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}`);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    客户端代码:

    <html>
      <head>
        <meta charset="UTF-8">
        <title>WebRTC Exampletitle>
      head>
      <body>
        <h1>WebRTC Exampleh1>
        <div>
          <video id="localVideo" autoplay>video>
          <video id="remoteVideo" autoplay>video>
        div>
        <div>
          <button id="callButton">Callbutton>
          <button id="hangupButton" disabled>Hang Upbutton>
        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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    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);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    订阅者端代码:

    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);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    如何确保这种通信的安全

    安全性对于任何实时通信应用程序都是至关重要的。可以使用crypto模块,用于保护客户端和服务器之间的通信。该模块提供加密和解密功能,使得在客户端和服务器之间发送加密消息成为可能。

    此外,每种类型都有模块,例如,在 WebSocket 中,有ws模块,安全的方法是用https而不是http包装它。

    结论

    Node.js 因其速度、可扩展性和可靠性而成为构建实时通信应用程序的绝佳选择。其事件驱动架构使得同时处理多个连接成为可能,并且V8 JavaScript引擎的使用确保了高性能能力。在 socket.io 等库的帮助下,使用 Node.js 构建实时通信应用程序非常简单。

    然而,在处理实时通信应用程序时,安全性至关重要,并且必须使用加密来保护客户端和服务器之间的通信。

    还提供了实现实时数据通信的各种方法,每种方法都有自己的一组功能和优点。选择正确的方法取决于您的应用程序的具体要求。socket.ioWebSockets 是最流行的实时通信方法,而服务器发送事件、WebRTCMQTT 适用于特定用例。

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

  • 相关阅读:
    网络编程 day05 (linux )数据库 sqlite3 的下载 与使用命令,和在程序中运用sqlite3
    vue3的基本使用(超详细)
    ceph 认证
    盈利背后,美团渴望第二曲线
    synchronized锁的四种状态及优化存储
    Java二分查找
    深入理解Linux内核select多路复用原理
    LeetCode算法心得——最短且字典序最小的美丽子字符串(枚举的思想)
    数据平台建设的痛点,如何进行元数据治理?
    vue中computed和watch
  • 原文地址:https://blog.csdn.net/qq_42880714/article/details/134023981