NodeJS Datagrams (UDP)

Home / NodeJS Datagrams (UDP)

NodeJS Datagrams (UDP)

December 9, 2015 | Article | No Comments

UDP is a connectionless protocol that does not provide the delivery characteristics that TCP does. When sending UDP packets, there is no guarantee for the order of packets and no guarantee for all packets will arrive. This may lead to conclusion that there is possibility that packets are arrive in random order or packets are incomplete.

On the other hand, UDP can be quite be useful in certain cases, like when we want to broadcast data, when we don’t need strict quality of delivery and sequence or even when we don’t know the address of our peers.

NodeJS has ‘dgram’ module to support Datagram transmission.

Datagram Server

A server listening to UDP port can be:

var dgram = require('dgram');

var server = dgram.createSocket('udp4');
server.on('message', function(message, rinfo) {
    console.log('server got message: ' + message +
                ' from ' + rinfo.address + ':' + rinfo.port);
});

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

server.bind(4002);

The createSocket function accepts the socket type as the first argument, which can be either “udp4” (UDP over IPv4), “udp6” (UDP over IPv6) or “unix_dgram” (UDP over UNIX domain socket).

When you run the script, you will see the server address, port, and then wait for messages.

We can test it using a tool like netcat:

echo 'hello' | netcat -c -u -w 1 localhost 4002

This sends an UDP packet with “hello” to localhost port 4002 which our program listen to. You should then get the server print out like:

server got message: hello
from 127.0.0.1:54950

Datagram Client

To create an UDP client to send UDP packets, we can do something like:

var dgram = require('dgram');

var client = dgram.createSocket('udp4');

var message = new Buffer('this is a message');
client.send(message, 0, message.length, 4002, 'localhost');
client.close();

Here we are creating a client using the same createSocket function we did to create the client, with difference we don’t bind.

You have to be careful not to change the buffer you pass on client.send before the message has been sent. If you need to know when your message has been flushed to the kernel, you should pass a callback function when the buffer may be reused.

client.send(message, 0, message.length, 4002, 'localhost', function() {
    // buffer can be reused now
});

Since we are not binding, the message is sent from random UDP port. If we want to send from a specific port, we use client.bind(port).

var dgram = require('dgram');

var client = dgram.createSocket('udp4');

var message = new Buffer('this is a message');
client.bind(4001);
client.send(message, 0, message.length, 4002, 'localhost');
client.close();

The port binding on the client really mixes what a server and client are, but it can be useful for maintaining conversations like this:

var dgram = require('dgram');

var client = dgram.createSocket('udp4');

var message = new Buffer('this is a message');
client.bind(4001);
client.send(message, 0, message.length, 4002, 'localhost');
client.on('message', function(message, rinfo) {
    console.log('and got the response: ' + message);
    client.close();
});

Here we are sending a message and also listening to messages. When we receive one message we close the client.

Don’t forget that UDP is unreliable. Whatever protocol we devise on top of it, it has possibility of lost and out of order.

Datagram Multicast

One of the interesting uses of UDP is to distribute message to several nodes using only one network message. This is multicast. Message multicasting can be useful when we don’t want to need to know the address of all peers. Peers just have to “tune in” and listen to multicast channel.

Nodes can report their interest in listening to certain multicast channels by “tuning” into that channel. In IP addressing there is a space reserved for multicast addresses. In IPv4 the range is between 224.0.0.0 and 239.255.255.255, but some of these are reserved. 224.0.0.0 through 224.0.0.255 is reserved for local purposes (as administrative and maintenance tasks) and the range 239.0.0.0 to 239.255.255.255 has also been reserved for “administrative scoping”.

Receiving Multicast Message

To join a multicast address, for example 230.1.2.3, we can do something like this:

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

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

server.addMembership('230.1.2.3');
server.bind(4002);

We say to the kernel that this UDP socket should receive multicast message for the multicast address 230.1.2.3. When calling the addMembership, we can pass the listening interface as an optional second argument. If omitted, Node will try to listen on every public interface.

The we can test the server using netcat like this:

echo 'hello' | netcat -c -u -w 1 230.1.2.3

Sending Multicast Message

To send a multicast message we simply have to specify the multicast address:

var dgram = require('dgram');

var client = dgram.createSocket('udp4');

var message = new Buffer('this is a message');
client.setMulticastTTL(10);
client.send(message, 0, message.length, 4002, '230.1.2.3');
client.close();

Here, besides sending the message, we previously set the Multicast time-to-live to 10 (an arbitrary value here). This TTL tells the network how many hops (routers) it can travel through before it is discard. Every time an UDP packet travels through a hop, TTL counter is decremented and if 0 is reached, the packet is discard.

, ,

About Author

about author

xathrya

A man who is obsessed to low level technology.

Leave a Reply

Your email address will not be published. Required fields are marked *

Social media & sharing icons powered by UltimatelySocial