NodeJS UDP Multicast How to
Asked Answered
C

3

32

I'm trying to send a UDP Multicast Packet to: 230.185.192.108 so everyone subscribed will receive. A bit stuck. I believe it's broadcasting correctly, but can't seem to pick anything up with any client.

Server:

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();
}

Client

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);

References More info on NodeJS Datagram

Cowboy answered 2/1, 2013 at 22:54 Comment(6)
Works just fine for me. Perhaps firewall or routing issues?Fauces
Hey Marcus, You're able to pickup the multicasted server messages after you subscribe to 230.185.192.108?Cowboy
Yep. I've only tried it locally on the same machine, but the client gets the messages. Edit: Could be worth noting that I used port 61088 instead of 8088 due to privileges.Fauces
Your title says multicast but your question says broadcast. Which is it?Gloomy
I found binding the listener to the multicast address - e.g. client.bind(PORT, '230.185.192.108') - worked. I did not need to specify HOST in the addMembership() call. (Running both processes on the same host, fwiw.)Aloisia
Your "client" is bound to a host and port, listening for messages. Your "server" is initiating communication by sending original messages. These notions of client and server seem semantically reversed to me.Polyclitus
C
15

Changed:

client.addMembership('230.185.192.108');

to

client.addMembership('230.185.192.108',HOST); //Local IP Address
Cowboy answered 3/1, 2013 at 2:45 Comment(4)
how does that work? If the HOST is not specified, the OS should try to bind to all applicable interfaces, so by specifying only one HOST, we only restrict the interfaces that the OS will bind to, right?Melo
If HOST is not specified, it picks one at random apparently: github.com/nodejs/node/pull/7244/filesHeavyhearted
@WillemMulder You are thinking of TCP. UDP multicast doesn't work like that. This isn't a TCP bind, it s a UDP multicast group join.Gloomy
@EJP Yes it's UDP, and a group is usually joined on a specific interface (identified by setting the HOST variable). I was wondering how making the addMembership more restrictive would work to fix this issue, but Segfault pointed out that leaving out the HOST variable doesn't bind to all interfaces but to one interface at random. That's odd behaviour, and that's why specifying the HOST is fixing the problem because now the behaviour becomes predictable.Melo
D
14

This answer is old, but shows up high on Google's search results. With Node v4.4.3, the server example fails with error EBADF. The complete working block of code is listed below:

Server:

//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...");
}

Client:

//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);

For the novices like me, client.bind(PORT,HOST); is the important bit. I couldn't get the client to receive anything when bound to HOST=127.0.0.1, but worked when the IP address was used. Again, HOST if excluded, the example won't work when testing using a single machine (client will throw EADDRINUSE error)

Divert answered 31/3, 2017 at 22:9 Comment(1)
Change dgram.createSocket('udp4') to dgram.createSocket({ type: 'udp4', reuseAddr: true }) and you will be able to remove HOST variable and get rid of EADDRINUSE error on the single mahine.Bushey
C
0

The solution provided here was not working for me, while this gist worked right out of the box: https://gist.github.com/ciaranj/9056285

I copied that here for convenience, all credits should go to @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...");
}
Chem answered 5/12, 2022 at 10:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.