R.Costa R.Costa - 3 months ago 16
Node.js Question

Node.js broadcasting twice

I'm giving my first steps with node.js. I'm trying to implement a simple chat room to get the basics, but can't figure out why after every broadcast, a second (empty) message is automatically sent. This behaviour happens most of the time but not always. I'm using Netbeans in Windows, with Putty to simulate the client connections.

Console output:

Server running
::1:60616 joined
::1:60617 joined
-----------
Broadcasting:
hello
-----------
Broadcasting:


-----------
Broadcasting:
goodbye
-----------
Broadcasting:


-----------


Client 1:

Hi ::1:60616!
hello
goodbye


Client 2:

Hi ::1:60617!
::1:60616 says hello::1:60616 says
::1:60616 says goodbye::1:60616 says


Code

var net = require('net');

var chatServer = net.createServer();
var clientList = [];

console.log('Server running');

chatServer.on('connection', function (client) {

client.name = client.remoteAddress + ':' + client.remotePort;
client.write('Hi ' + client.name + '!\n');

console.log(client.name + ' joined');

clientList.push(client);

client.on('data', function (data) {

console.log('Broadcasting: ');
console.log(data.toString());
console.log('-----------');

broadcast(data, client);
});

client.on('end', function () {
console.log(client.name + ' quit');
clientList.splice(clientList.indexOf(client), 1);
});

client.on('error', function (e) {
console.log(e);
});
});

function broadcast(message, sender) {

var text = sender.name + " says " + message;

var cleanup = [];

clientList.forEach(function (client) {

if (client !== sender) {

if (client.writable) {
client.write(text);
} else {
cleanup.push(client);
client.destroy();
}
}
});

cleanup.forEach(function (client) {
clientList.splice(clientList.indexOf(client), 1);
});
}

chatServer.listen(9000);

Answer

You can't rely on the raw data event to present you with "well-rounded" chunks of data. It may come in pieces, and you can't necessarily control how large those pieces are, or that they get split on particular boundaries.

However, there are modules that can help you, for instance split, which will split the data into separate (full) lines:

const split = require('split');
...
client.pipe(split()).on('data', function (data) {
  // `data` is now a separate line
  console.log('Broadcasting: ');
  console.log(data.toString());
  console.log('-----------');

  broadcast(data, client);
});