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}`);
  });
});
相关推荐
用户938515635072 小时前
从零理解 React Router v6:每一个 API 都是怎么工作的
前端·javascript·全栈
abbgogo3 小时前
TCP/IP、OSI 与常见网络协议知识点总结
网络·网络协议·计算机网络
李昊哲小课3 小时前
fastapi sse websocket 奶茶店实时订单看板
人工智能·python·websocket·网络协议·fastapi·sse
用户059540174463 小时前
Redis缓存回滚踩坑实录:一个配置失误,让我在凌晨3点丢了3000条数据
前端·css
星蓝_starblue4 小时前
零服务器、零数据库!开源growth-board,利用GitHub自动管理刷题/学习/求职全流程
服务器·数据库·程序人生·系统架构·node.js·github·改行学it
kyriewen4 小时前
别再这样写条件渲染了——你的React组件里藏着这5种定时炸弹
前端·javascript·react.js
FungLeo4 小时前
Flutter 接入 Alice 调试浮窗:一个顶层 final 抢跑,把 release 网络整没了
网络·flutter
IT_陈寒5 小时前
Redis缓存击穿把我坑惨了,原来这样设过期时间才靠谱
前端·人工智能·后端
用户938515635075 小时前
从"坐电梯"到"前端路由"——深入理解 Hash 路由原理
前端·typescript·全栈
梦想CAD控件5 小时前
网页端CAD的图形选择、编辑与夹点操作教程
前端·javascript·node.js