NodeJS UDP组播如何实现?

32

我试图向地址为230.185.192.108的UDP组播地址发送数据包,以便所有已订阅的客户端都能接收。但目前遇到了一些困难,虽然我相信广播已经正确发送,但是使用任何客户端似乎都无法接收到。

服务器:

var news = [
   "Borussia Dortmund wins German championship",
   "Tornado warning for the Bay Area",
   "More rain for the weekend",
   "Android tablets take over the world",
   "iPad2 sold out",
   "Nation's rappers down to last two samples"
];

var dgram = require('dgram'); 
var server = dgram.createSocket("udp4"); 
server.bind();
server.setBroadcast(true)
server.setMulticastTTL(128);
server.addMembership('230.185.192.108'); 

setInterval(broadcastNew, 3000);

function broadcastNew() {
    var message = new Buffer(news[Math.floor(Math.random()*news.length)]);
    server.send(message, 0, message.length, 8088, "230.185.192.108");
    console.log("Sent " + message + " to the wire...");
    //server.close();
}

客户端

var PORT = 8088;
var HOST = '192.168.0.102';
var dgram = require('dgram');
var client = dgram.createSocket('udp4');

client.on('listening', function () {
    var address = client.address();
    console.log('UDP Client listening on ' + address.address + ":" + address.port);
    client.setBroadcast(true)
    client.setMulticastTTL(128); 
    client.addMembership('230.185.192.108');
});

client.on('message', function (message, remote) {   
    console.log('A: Epic Command Received. Preparing Relay.');
    console.log('B: From: ' + remote.address + ':' + remote.port +' - ' + message);
});

client.bind(PORT, HOST);

参考资料 有关NodeJS数据报的更多信息


对我来说完全正常。也许是防火墙或路由问题? - mekwall
嘿,马库斯,你订阅了230.185.192.108后,能够接收到多播服务器消息吗? - Taurian
是的。我只在同一台机器上本地尝试过,但客户端可以收到消息。编辑:值得注意的是,由于权限问题,我使用了端口61088而不是8088。 - mekwall
1
我将client.addMembership('230.185.192.108');更改为client.addMembership('230.185.192.108','HOST');,这似乎解决了问题。我也在本地进行所有操作。马库斯,再次感谢你的帮助。 - Taurian
3
你的标题说的是“多播”,但你的问题中说的是“广播”。究竟是哪一个? - user207421
显示剩余2条评论
3个回答

15

更改:

client.addMembership('230.185.192.108');

client.addMembership('230.185.192.108',HOST); //Local IP Address

如果没有指定HOST,操作系统应该尝试绑定到所有适用的接口,因此仅指定一个HOST,我们只限制了操作系统将要绑定的接口,对吗? - Willem Mulder
3
如果未指定主机,它似乎会随机选择一个,参考链接:https://github.com/nodejs/node/pull/7244/files。 - Segfault
@WillemMulder 你在考虑TCP。UDP组播不是这样工作的。这不是一个TCP绑定,而是一个UDP组播组加入。 - user207421
@EJP 是的,这是UDP,并且通常在特定接口上加入组(通过设置HOST变量来识别)。我想知道如何使addMembership更具限制性以解决此问题,但Segfault指出,省略HOST变量不会绑定到所有接口,而是随机绑定到一个接口。这是奇怪的行为,这就是为什么指定HOST可以解决问题的原因,因为现在行为变得可预测。 - Willem Mulder

14

这篇答案很老,但在谷歌搜索结果中排名较高。 在 Node v4.4.3 版本中,服务器示例会出现 EBADF 错误。下面列出了完整的工作代码块:

服务器:

//Multicast Server sending messages
var news = [
   "Borussia Dortmund wins German championship",
   "Tornado warning for the Bay Area",
   "More rain for the weekend",
   "Android tablets take over the world",
   "iPad2 sold out",
   "Nation's rappers down to last two samples"
];

var PORT = 41848;
var MCAST_ADDR = "230.185.192.108"; //not your IP and should be a Class D address, see http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml
var dgram = require('dgram'); 
var server = dgram.createSocket("udp4"); 
server.bind(PORT, function(){
    server.setBroadcast(true);
    server.setMulticastTTL(128);
    server.addMembership(MCAST_ADDR);
});

setInterval(broadcastNew, 3000);

function broadcastNew() {
    var message = new Buffer(news[Math.floor(Math.random()*news.length)]);
    server.send(message, 0, message.length, PORT,MCAST_ADDR);
    console.log("Sent " + message + " to the wire...");
}

客户:

//Multicast Client receiving sent messages
var PORT = 41848;
var MCAST_ADDR = "230.185.192.108"; //same mcast address as Server
var HOST = '192.168.1.9'; //this is your own IP
var dgram = require('dgram');
var client = dgram.createSocket('udp4');

client.on('listening', function () {
    var address = client.address();
    console.log('UDP Client listening on ' + address.address + ":" + address.port);
    client.setBroadcast(true)
    client.setMulticastTTL(128); 
    client.addMembership(MCAST_ADDR);
});

client.on('message', function (message, remote) {   
    console.log('MCast Msg: From: ' + remote.address + ':' + remote.port +' - ' + message);
});

client.bind(PORT, HOST);

对于像我这样的新手,client.bind(PORT,HOST)是重要的部分。当绑定到HOST=127.0.0.1时,我无法让客户端接收任何内容,但当使用 IP 地址时它可以工作。同样,如果排除 HOST,当在单台机器上测试时,示例将无法工作(客户端将抛出 EADDRINUSE 错误)。


1
dgram.createSocket('udp4') 更改为 dgram.createSocket({ type: 'udp4', reuseAddr: true }),您就可以删除 HOST 变量并消除单台计算机上的 EADDRINUSE 错误。 - Ilia Liachin

0
这里提供的解决方案对我无效,但是这个gist可以直接使用: https://gist.github.com/ciaranj/9056285 为了方便,我将其复制在这里,所有的功劳应归于@ciaranj。

client.js:

var PORT = 5007;
var dgram = require('dgram');
var client = dgram.createSocket({ type: 'udp4', reuseAddr: true })

client.on('listening', function () {
    var address = client.address();
    console.log('UDP Client listening on ' + address.address + ":" + address.port);
    client.setBroadcast(true)
    client.setMulticastTTL(128);
    client.addMembership('224.1.1.1');
});

client.on('message', function (message, remote) {
    console.log('A: Epic Command Received. Preparing Relay.');
    console.log('B: From: ' + remote.address + ':' + remote.port + ' - ' + message);
});

client.bind(PORT);

server.js:

var news = [
    "Borussia Dortmund wins German championship",
    "Tornado warning for the Bay Area",
    "More rain for the weekend",
    "Android tablets take over the world",
    "iPad2 sold out",
    "Nation's rappers down to last two samples"
];

var dgram = require('dgram');
var server = dgram.createSocket("udp4");
server.bind(function () {
    server.setBroadcast(true)
    server.setMulticastTTL(128);
    setInterval(broadcastNew, 3000);
});

function broadcastNew() {
    var message = new Buffer.from(news[Math.floor(Math.random() * news.length)]);
    server.send(message, 0, message.length, 5007, "224.1.1.1");
    console.log("Sent " + message + " to the wire...");
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接