16

I'm building a simple system like a realtime news feed, using node.js + socket.io.

Since this is a "read-only" system, clients connect and receive data, but clients never actually send any data of their own. The server generates the messages that needs to be sent to all clients, no client generates any messages; yet I do need to broadcast.

The documentation for socket.io's broadcast (end of page) says

To broadcast, simply add a broadcast flag to emit and send method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.

So I currently capture the most recent client to connect, into a variable, then emit() to that socket and broadcast.emit() to that socket, such that this new client gets the new data and all the other clients. But it feels like the client's role here is nothing more than a workaround for what I thought socket.io already supported.

Is there a way to send data to all clients based on an event initiated by the server?

My current approach is roughly:

var socket;

io.sockets.on("connection", function (s) {
  socket = s;
});

/* bunch of real logic, yadda yadda ... */

myServerSideNewsFeed.onNewEntry(function (msg) {
  socket.emit("msg", { "msg" : msg });
  socket.broadcast.emit("msg", { "msg" : msg });
});

Basically the events that cause data to require sending to the client are all server-side, not client-side.

d11wtq
  • 34,788
  • 19
  • 120
  • 195

2 Answers2

21

Why not just do like below?

io.sockets.emit('hello',{msg:'abc'});
Lucio Paiva
  • 19,015
  • 11
  • 82
  • 104
user482594
  • 16,878
  • 21
  • 72
  • 108
  • When I tried that I got an error that `io.sockets.emit` is not a defined function. – d11wtq Dec 21 '11 at 12:31
  • 2
    Hmm, seems I actually tried `io.sockets.broadcast.emit()`, my bad, this does seem to work! – d11wtq Dec 21 '11 at 12:33
  • I'll change the selected answer as this is a lot simpler, thanks. – d11wtq Dec 21 '11 at 12:34
  • If you have something simple indeed that will work, if you need to iterate through the sockets and only sent a message if a certain condition is met then my solution is more general. – alessioalex Dec 21 '11 at 12:35
  • @alessioalex, thanks, I appreciate your solution; I learnt something new. However, in this case I'm specifically trying to avoid the need to iterate. This is a really simple system but needs to scale as best as possible, as it's visible site-wide and is updated every 7 seconds. – d11wtq Dec 21 '11 at 12:43
  • Absolutely, `io.sockets.broadcast.emit` is the best fit here. – alessioalex Dec 21 '11 at 12:48
  • 1
    As of v1.0.4, I am able to simply write ``io.emit('hello',{msg:'abc'})`` and it works just as well. – Lucio Paiva Jun 19 '14 at 03:33
5

Since you are emitting events only server side, you should create a custom EventEmitter for your server.

var io = require('socket.io').listen(80);
    events = require('events'),
    serverEmitter = new events.EventEmitter();

io.sockets.on('connection', function (socket) {
  // here you handle what happens on the 'newFeed' event
  // which will be triggered by the server later on
  serverEmitter.on('newFeed', function (data) {
    // this message will be sent to all connected users
    socket.emit(data);
  });
});

// sometime in the future the server will emit one or more newFeed events
serverEmitter.emit('newFeed', data);

Note: newFeed is just an event example, you can have as many events as you like.

Important

The solution above is better also because in the future you might need to emit certain messages only to some clients, not all (thus need conditions). For something simpler (just emit a message to all clients no matter what), io.sockets.broadcast.emit() is a better fit indeed.

alessioalex
  • 62,577
  • 16
  • 155
  • 122
  • Ah, I was doing something very similar before, albeit with more of a conventional observer design pattern (it's my first day using node), but I was concerned that the loop was inefficient. New messages are broadcast every 7 seconds to around 10,000 clients. – d11wtq Dec 21 '11 at 11:50
  • I assumed broadcast used an efficient algorithm, but maybe it's just an abstraction. I'll try your approach ;) – d11wtq Dec 21 '11 at 11:50
  • A bit off-topic, but do I need to handle disconnect, or will socket.io/node take care of it for me? Seems like I would end up with dead event observers. – d11wtq Dec 21 '11 at 11:52
  • You don't need to handle disconnect. – alessioalex Dec 21 '11 at 12:35