Multicasting with Node and WebSocket

Objective: Implementation WebSocket with ws npm module would be intuitive and it supports broadcasting by default. In practice you might want to separate group from clients and do not want to open too much listening ports.

Main Idea:

  1. Use sub-protocol to group [1]. (yes, it’s hacking)
  2. Use node-uuid to identify each client to register

Work:

  1. Server initialization: Most example code will skip the hadleProtocols parameter, but we would use this for hacking. :-)
var wss = new WebSocketServer({
port: SERVER_PORT,
handleProtocols: “your_chatroom_name”
});

2. On registration: WebSocket server will determinate incoming client use ‘sub-protocol’ or not, set broadcast if not set. Then do the registration (save to the client[] ).

wss.on(‘connection’, function(ws) {
console.log(‘on connection, client protocol: ‘ + ws.protocol)
var client_uuid = uuid.v4();
var nickname = “AnonymousUser” + clientIndex;
var client_protocol = (ws.protocol) ? ws.protocol : ‘broadcast’;
console.log(‘set protocol: ‘ + client_protocol);
clientIndex += 1;
clients.push({
“id”: client_uuid,
“ws”: ws,
“nickname”: nickname,
“channel”: client_protocol
});

3. On communication: The mainly function wsMulticast() would:

3.1 find message originator channel

3.2 send message to the same channel

function wsMulticast(target_channel, client_uuid, nickname,  message) {
    // find message originator channel
for (var i = 0; i < clients.length; i++) {
var clientSocket = clients[i].ws;
if (clients[i]["id"] == client_uuid) {
console.log('originator channe: ' + clients[i]["channel"]);
target_channel = clients[i]["channel"];
break;
} else {
//
}
}
console.log('target channel changed: ' + target_channel);

for (var i = 0; i < clients.length; i++) {
var clientSocket = clients[i].ws;
if (clients[i]["channel"] == target_channel) {
console.log('multicast to: ' + target_channel);
if ((clientSocket.readyState === WebSocket.OPEN)) {
clientSocket.send(JSON.stringify({
"channel": clients[i].channel,
"id": client_uuid,
"nickname": nickname,
"message": message
}));
}
} else {
//console.log('swallow it...');
}
}
}

4. Do multicast when server receives message from client:

ws.on(‘message’, function(message) {
...
wsMulticast(wss.options.handleProtocols, client_uuid, nickname, message);
}

Test:

  1. Simply use wscat (npm install -g wscat)
$ wscat -c “ws://localhost:6789” -s “chat_room_001”

2. Sample usage in JavaScript:

var device = new WebSocket(‘ws://localhost:8080’, ‘chatroom_001’);

Github: please send issue and suggestion on this repo. :-)

References: