Node.js UDP通信 dgram 组播

先说一些大家喜闻乐见的废话

UDP是一种速度快,但可靠性低的一种通信方式,音视频,游戏,基本都在使用它,更具体的废话比如说OSI七层模型之类的就不多说了,因为计网都教过

在Node.js中,常使用dgram这个库做UDP通信,dgram是由node官方封装的,无需安装,require引入使用即可

dgram 数据报 | Node.js v22 文档

UDP在日常中分为两种使用方式,一种是单播,一种是组播(多播)

单播是指,A设备只能跟B设备通信,相反则不行,类似于单工

组播(广播)是指,AB设备互相都能通信,没有限制

使用组播时,接收消息的端口和发送消息的端口要一致,也就是bind和send函数中传递的端口一致,在ip地址方面是组播地址就行,我这边因为是局域网通信,所以用了224.0.0.5来通过路由器实现局域网内组播

下面是组播的代码,通用性还是比较高的,避免因本地有多张网卡分属于不同的IP段,造成消息发出去接不到的情况,比如说我本机是192.168.124.55,局域网其他电脑也都是192.168.124开头的,虚拟网卡是192.168.54.1,本机是有可能连到虚拟网卡并且从它的IP段发送数据的,就会造成一种看着是本机发送数据了,但是同局域网的电脑收不到的情况

javascript 复制代码
const PORT = 20000;
const MULTICAST_ADDR = "224.0.0.5";
const BaseSourceData = require("../pojo/index.js");

const dgram = require("dgram");
const process = require("process");
const CWS = require("../ws/index.js");
const cws = CWS;

let arr = [];
const getLocalIPV4 = (ver = 4) => {
  const interfaces = require("os").networkInterfaces();
  let ips = [];
  for (let netDev in interfaces) {
    for (let netProt of interfaces[netDev]) {
      if (
        netProt.family === `IPv${ver}` &&
        !netProt.internal &&
        netProt.address !== "127.0.0.1"
      ) {
        ips.push(netProt.address);
      }
    }
  }
  return ips;
};

getLocalIPV4().forEach((item, index) => {
  console.log("🚀 ~ getLocalIPV4 ~ item: server", item);
  arr[index] = dgram.createSocket("udp4", { type: "udp4", reuseAddr: true });

  arr[index].bind(PORT, item);

  arr[index].on("listening", function () {
    arr[index].addMembership(MULTICAST_ADDR);
    arr[index].setBroadcast(true);
    setInterval(() => {
      sendMessage(address);
    }, 2500);
    const address = arr[index].address();
    console.log(
      `UDP socket listening on ${address.address}:${address.port} pid: ${
        process.pid
      }`
    );
  });

  function sendMessage(address) {
    const findUserObj = new BaseSourceData({
      time: Date.now(),
      userName: cws.userName,
      startTime: cws.startTime,
      avatar: cws.avatar,
    });
    const message = Buffer.from(JSON.stringify(findUserObj));
    arr[index].send(
      message,
      0,
      message.length,
      PORT,
      MULTICAST_ADDR,
      function () {
        console.info(`Sending message "${message}"`);
      }
    );
  }

  arr[index].on("message", function (message, rinfo) {
    if (getLocalIPV4().some((ip) => ip === rinfo.address)) {
      return;
    }
    let tempObj = JSON.parse(message.toString());
    tempObj.data.ip = rinfo.address;
    const findUserObj = JSON.stringify(tempObj);
    if (!!cws.wsObj) {
      cws.wsObj.send(findUserObj);
    }
    console.info(`Message from: ${rinfo.address}:${rinfo.port} - ${message}`);
  });
});
相关推荐
Dontla6 分钟前
Docker多共享网络配置策略(Docker多网络、Docker networks、Docker Compose网络、Docker网络、Docker共享网络)
网络·docker·容器
吃饭最爱26 分钟前
html的基础知识
前端·html
我没想到原来他们都是一堆坏人27 分钟前
(未完待续...)如何编写一个用于构建python web项目镜像的dockerfile文件
java·前端·python
LUCIAZZZ32 分钟前
HTTPS优化简单总结
网络·网络协议·计算机网络·http·https·操作系统
wanhengidc44 分钟前
云手机运行流畅,秒开不卡顿
运维·网络·科技·游戏·智能手机
前端Hardy1 小时前
HTML&CSS:有趣的漂流瓶
前端·javascript·css
前端Hardy1 小时前
HTML&CSS :惊艳 UI 必备!卡片堆叠动画
前端·javascript·css
无羡仙1 小时前
替代 Object.freeze 的精准只读模式
前端·javascript
名誉寒冰1 小时前
TCP 拥塞控制与四次挥手解析
网络·网络协议·tcp/ip
web前端1231 小时前
Java客户端开发指南 - 与Web开发对比分析
前端