nodejs组播通信
最近想学习一下nodejs传输层通信的内容,在网上找了一些资料自己学习着做了一下
[AY-Node.js]写给自己的NodeJs-通讯系统-udp-dgram模块
Node.js:dgram模块实现UDP通信
Node.js Manual & Documentation
nodejs可以支持TCP/UDP的通信,其中tcp可以通过net模块实现,udp通过dgram模块实现。这里主要想试试组播通信,就先试试dgram的UDP通信。
UDP组播
在tcp/ip协议簇中IANA规定了D类ip地址分配给组播,具体就是224.0.0.0-239.255.255.255。每个ip可以标记一个组播组,由IGMP协议维护。组播ip地址具体又有几种细分:
224.0.0.0~224.0.0.255//永久组地址,地址224.0.0.0保留不做分配,其它地址供路由协议使用;
224.0.1.0~224.0.1.255//公用组播地址,可以用于Internet;
224.0.2.0~238.255.255.255//用户可用的组播地址(临时组地址),全网范围内有效;
239.0.0.0~239.255.255.255//本地管理组播地址,仅在特定的本地范围内有效。
通过dgram模块中addMembership()方法将socket加入组播组中,dropMembership()方法退出组播组。只有加入组播组才能接收到组播数据。
实现
//代码是参考的Node.js:dgram模块实现UDP通信
服务端代码:
/*server*/
const dgram = require('dgram');
const server = dgram.createSocket('udp4'); //创建udp服务器
const multicastAddr = '224.100.100.100';
//以下server.on 都是在监听不同信号
server.on('close',()=>{ // ()=> 是 ES6的箭头函数,写成 function()也是可以的
console.log('socket已关闭');
});
server.on('error',(err)=>{
console.log(err);
});
server.on('listening',()=>{
console.log('socket正在监听中...');
server.addMembership(multicastAddr); //加入组播组
server.setMulticastTTL(128);
});
server.on('message',(msg,rinfo)=>{
console.log(`receive message from ${rinfo.address}:${rinfo.port}`);
});
function sendMsg(){
var message = '大家好啊,我是服务端.';
server.send(message,0,message.length,8061,multicastAddr);
//通过server.send发送组播
//参数分别是,数据(buffer或者string),偏移量(即开始发送的位子),数据长度,接收的端口,组播组
}
server.bind(8060); //绑定端口,不绑定的话也可以send数据但是无法接受
//循环发送
setInterval(()=>{
sendMsg();
console.log("send message");
},1500);
客户端代码:
/*client*/
//基本与服务端类似
const dgram = require('dgram');
const client = dgram.createSocket('udp4');
const multicastAddr = '224.100.100.100';
client.on('close',()=>{
console.log('socket已关闭');
});
client.on('error',(err)=>{
console.log(err);
});
client.on('listening',()=>{
console.log('socket正在监听中...');
client.addMembership(multicastAddr);
});
client.on('message',(msg,rinfo)=>{
console.log(`receive message from ${rinfo.address}:${rinfo.port}:${msg}`);
});
client.bind(8061);
遇到的问题
同一台主机上服务器与客户端可以通信,但不同主机间不能通信,wireshark抓不到数据包。
猜测可能是主机上局域网太多,服务器选择了不同的网卡,导致不在一个网段内。抓取了数据包源IP,证实了使用的是另一个虚拟网段。禁用其他网段的网卡后问题解决。
UDP广播
广播地址
广播地址比组播简单,IP协议中将主机号全为1的地址留给了广播。利用主机号和子网掩码可以算出当前网段的广播地址。
IP地址:10.108.92.2
子网掩码:255.255.252.0
子网掩码后十位为零 -> 即主机号为后十位 -> 将IP地址的后十位置一 -> 得到广播地址10.108.95.255
最后代码如下,通过上面组播的客户端和服务器端代码也可以看得很清楚了,其实UDP通信中并不建立连接,不用过度区分服务端和客户端。发送数据的就是服务端,接收的就是客户端
var dgram = require('dgram');
var server = dgram.createSocket('udp4');
server.on('close',()=>{
console.log('socket已关闭');
});
server.on('error',(err)=>{
console.log(err);
});
server.on('listening',()=>{
console.log('socket正在监听中...');
server.setBroadcast(true);//开启广播
server.setTTL(128);//路由一跳TTL减一,减到零抛弃数据包
server.send('大家好啊,我是服务端.',8061,'10.108.95.255');
//在send {msg=close} 可以发送 colse 事件
});
//通过message事件接收数据,
server.on('message',(msg,rinfo)=>{
console.log(`receive message from ${rinfo.address}:${rinfo.port}`);
});
//绑定,要接收数据的话必须绑定
server.bind('8060','10.108.92.2');