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段发送数据的,就会造成一种看着是本机发送数据了,但是同局域网的电脑收不到的情况
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}`);
});
});