Send Broadcast datagram
Asked Answered
T

4

24

I need to send a broadcast datagram to all machine (servers) connected to my network.

I'm using NodeJS Multicast

Client

var dgram = require('dgram');
var message = new Buffer("Some bytes");
var client = dgram.createSocket("udp4");
client.send(message, 0, message.length, 41234, "localhost");
// If I'm in the same machine 'localhost' works
// I need to do something 192.168.0.255 or 255.255.255
client.close();

Servers

 var dgram = require("dgram");

 var server = dgram.createSocket("udp4");

 server.on("message", function (msg, rinfo) {
   console.log("server got: " + msg + " from " +
     rinfo.address + ":" + rinfo.port);
 });

 server.on("listening", function () {
   var address = server.address();
   console.log("server listening " + address.address + ":" + address.port);
 });

 server.bind(41234);

Thanks.

Tragacanth answered 30/5, 2011 at 14:17 Comment(0)
R
22

I never used Node.js, but I do recall that with Berkely sockets (which seem to be the most widely used implementation of sockets) you need to enable the SO_BROADCAST socket option to be able to send datagrams to the broadcast address. Looking up the dgram documentation, there seems to be a function for it.

var client = dgram.createSocket("udp4");
client.setBroadcast(true);
client.send(message, 0, message.length, 41234, "192.168.0.255");

You might want to find out the broadcast address programmatically, but I can't help you with that.

Reposition answered 30/5, 2011 at 14:23 Comment(4)
If you use 255.255.255.255 it will act as the local broadcast address per RFC922. =)Antonio
weird. even with this change, the server never seems to receive anything from the client.Oriel
@Oriel You need to listen on 0.0.0.0, and then receiving will work.Firehouse
this will not work, client must be listening to do that : #9243457Ozmo
E
36

I spent a lot of time trying to be able to do UDP broadcasting and multicasting between computers. Hopefully this makes it easier for others since this topic is quite difficult to find answers for on the web. These solutions work in Node versions 6.x-12.x:

UDP Broadcasting

Calculate the broadcast address

Broadcast address = (~subnet mask) | (host's IP address) - see Wikipedia. Use ipconfig(Windows) or ifconfig(Linux), or checkout the netmask module.

Server (remember to change BROADCAST_ADDR to the correct broadcast address)

var PORT = 6024;
var BROADCAST_ADDR = "58.65.67.255";
var dgram = require('dgram');
var server = dgram.createSocket("udp4");

server.bind(function() {
    server.setBroadcast(true);
    setInterval(broadcastNew, 3000);
});

function broadcastNew() {
    var message = Buffer.from("Broadcast message!");
    server.send(message, 0, message.length, PORT, BROADCAST_ADDR, function() {
        console.log("Sent '" + message + "'");
    });
}

Client

var PORT = 6024;
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.on('message', function (message, rinfo) {
    console.log('Message from: ' + rinfo.address + ':' + rinfo.port +' - ' + message);
});

client.bind(PORT);

UDP Multicasting

Multicast addresses

Looking at the IPv4 Multicast Address Space Registry and more in-depth clarification in the RFC 2365 manual section 6, we find the appropriate local scope multicast addresses are 239.255.0.0/16 and 239.192.0.0/14 (that is, unless you obtain permission to use other ones).

The multicast code below works just fine on Linux (and many other platforms) with these addresses.

Most operating systems send and listen for multicasts via specific interfaces, and by default they will often choose the wrong interface if multiple interfaces are available, so you never receive multicasts on another machine (you only receive them on localhost). Read more in the Node.js docs. For the code to work reliably, change the code so you specify the host's IP address for the interface you wish to use, as follows:

Server - server.bind(SRC_PORT, HOST_IP_ADDRESS, function() ...

Client - client.addMembership(MULTICAST_ADDR, HOST_IP_ADDRESS);

Take a look at these supporting sources: NodeJS, Java, C#, and a helpful command to see which multicast addresses you are subscribed to - netsh interface ipv4 show joins.

Server

var SRC_PORT = 6025;
var PORT = 6024;
var MULTICAST_ADDR = '239.255.255.250';
var dgram = require('dgram');
var server = dgram.createSocket("udp4");

server.bind(SRC_PORT, function () {         // Add the HOST_IP_ADDRESS for reliability
    setInterval(multicastNew, 4000);
});

function multicastNew() {
    var message = Buffer.from("Multicast message!");
    server.send(message, 0, message.length, PORT, MULTICAST_ADDR, function () {
        console.log("Sent '" + message + "'");
    });
}

Client

var PORT = 6024;
var MULTICAST_ADDR = '239.255.255.250';
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.on('message', function (message, rinfo) {
    console.log('Message from: ' + rinfo.address + ':' + rinfo.port + ' - ' + message);
});

client.bind(PORT, function () {
    client.addMembership(MULTICAST_ADDR);   // Add the HOST_IP_ADDRESS for reliability
});

UPDATE: There are additional options for server.send (named socket.send in the docs). You can use a string for the msg instead of a Buffer, and depending on your version, several parameters are optional. You can also check whether an error has occurred in the callback function.

UPDATE: Since Node.js v6, new Buffer(str) is deprecated in favor of Buffer.from(str). The code above has been updated to reflect this change. If you are using an earlier version of Node, use the former syntax.

Experience answered 25/6, 2015 at 0:11 Comment(6)
I have a question regarding UDP Multicasting. Your example works well having only 1 client. But what should we change in order to have more clients that will receive the multicasted message form the server>? Thank you!Earlie
Sorry for the late reply. For multiple clients to receive the multicasted message, you don't need to do anything extra. Each client simply subscribes to the same multicast address (using the addMembership function) that the server sends the message to. All of the clients receive the message (with about a 99.9% success rate according to my experience, since UDP is not completely reliable).Experience
Thank you for your answer. But in my question I meant something different. My goal is to run multiple clients on the same machine (Mac OS) that all of them are members to MULTICAST_ADDR. That means that all clients must have the same PORT in order for multicasting to work. Using your code for UDP Multicasting I need somehow to reusePort to be able to run multiple times client.js. I managed to find in documentation of dgram.createSocket(options[, callback]) a option reuseAddr field but couldn't find anything about PORT. I would be thankful to you if you can provide such an exampleEarlie
I found the solution, sorry for waisting your time. Thank you! Solution ( client = dgram.createSocket({ type: 'udp4', reuseAddr: true }); )Earlie
Hi @Joseph238, it seems as though I am able to send messages to the multicast group (checked using tcpdump), but other machines connected to it are not receiving these messages. The two machines are on different subnets, but routers are taking into account multicast. Do you know what the problem could be?Jeremie
Hi @walksignison. You most likely need to set the multicast TTL. If you are not familiar with TTL, see this section from the Microsoft docs. Here's the syntax for setMulticastTTL from the Node docs. Also, have you checked first to make sure you able to send multicasts within the subnet using the same code? I like to try two machines connected to the same router.Experience
R
22

I never used Node.js, but I do recall that with Berkely sockets (which seem to be the most widely used implementation of sockets) you need to enable the SO_BROADCAST socket option to be able to send datagrams to the broadcast address. Looking up the dgram documentation, there seems to be a function for it.

var client = dgram.createSocket("udp4");
client.setBroadcast(true);
client.send(message, 0, message.length, 41234, "192.168.0.255");

You might want to find out the broadcast address programmatically, but I can't help you with that.

Reposition answered 30/5, 2011 at 14:23 Comment(4)
If you use 255.255.255.255 it will act as the local broadcast address per RFC922. =)Antonio
weird. even with this change, the server never seems to receive anything from the client.Oriel
@Oriel You need to listen on 0.0.0.0, and then receiving will work.Firehouse
this will not work, client must be listening to do that : #9243457Ozmo
B
14

I think since node 0.10.0 some things has changed this works for me now:

//var broadcastAddress = "127.255.255.255";
var broadcastAddress = "192.168.0.255";

var message = new Buffer("Some bytes");

var client = dgram.createSocket("udp4");
client.bind();
client.on("listening", function () {
    client.setBroadcast(true);
    client.send(message, 0, message.length, 6623, broadcastAddress, function(err, bytes) {
        client.close();
    });
});

Hope this helps somebody ;)

Bowls answered 27/3, 2013 at 13:32 Comment(1)
Thank you so much for this, this was driving me crazy. If this helps anyone else troubleshooting -- strangely, just simply creating the socket and calling send works just fine on Windows. Trying to run the same code on Raspberry Pi OS was throwing EACCES without going down this path of bind / setBroadcast.Victim
G
0

If you want a AUTOMATIC BROADCAST ADDRESS yo can do:

  const broadcastAddress = require('broadcast-address');

  const os = require("os")

  var PORT = 1234;
  var dgram = require('dgram');
  var server = dgram.createSocket("udp4");

  server.bind(function() {
      server.setBroadcast(true);
      setInterval(broadcastNew, 5000);
  });

  function broadcastNew() {
      var message = Buffer.from("Broadcast message!");
      Object.keys(os.networkInterfaces()).forEach(it=>{
        console.log(broadcastAddress(it));
        server.send(message, 0, message.length, PORT, broadcastAddress(it), function() {
          console.log("Sent '" + message + "'");
      });
      })
  }

This code will get a broadcast address for each interface on you server and send a message.

;) reguards

NOTE: dont forget install broadcast-address = "npm i broadcast-address"

Grievous answered 12/9, 2021 at 16:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.