Sending messages to certain clients with Socket.io

I recently started playing with Socket.io and it’s really easy to get up and running. Just copy and paste their example and run the server. Open the page and open the console to see your messages being passed back and forth. I wanted to make a small chat app to play with sending messages to specific users, and it was quite difficult to find out how to do it so I decided to create a small demo app on Github.

I started with their example to prove that everything should work. It all worked fine, so I moved on to keeping track of individual clients. It took me ages to realise that events are bound per socket. Once I realised that, I started digging into the socket object and realised that socket.id is the important bit. Push it into an array and you have an array of socket objects that you can write to.

var clients = [];
io.sockets.on('connection', function (socket) {
  clients.push(socket.id);
});

You write to each socket using io.sockets.connected(socket.id).emit("topic", data), so I decided to send a different message to the first two users connected after five seconds:

setTimeout(function(){
    io.sockets.connected(clients[0]).emit("greeting", "Howdy, User 1!");
    io.sockets.connected(clients[1]).emit("greeting", "Hey there, User 2");

    // If you're using Socket.io < 1.0, you need to use io.sockets.socket instead
    // io.sockets.socket(clients[0]).emit("greeting", "Howdy, User 1!");
}, 5000);

This worked fine (you can see the full commit here).

Finally, we needed to route messages to specific clients. I decided to use a username as the unique identifier for a socket, so store the data in an object like so:

var clients = {
    "mheap": {
        "socket": "1hu189dnfd"
    }
}

This means that I can now use io.sockets.connected(clients.mheap.socket).emit() to send messages just to myself. As the connection is established instantly when the page loads, there's no way to add metadata to a socket connection on connect (without using socket.auth and a session, which I'll cover some other time). As a result, I ended up listening for a "add-user" message and creating the client when I received it:

socket.on('add-user', function(data){
    clients[data.username] = {
      "socket": socket.id
    };
  });

You can see the entire thing in the github repo. The frontend depends on a CDN version of jQuery and is horribly written, but it works for demonstrating client management with socket.io.

If you want to give it a go, you can run the following commands:

$ git clone git@github.com:mheap/socketio-chat-example.git && cd socketio-chat-example && npm install && node app.js

Then open http://localhost:3000 in two browser windows, join the chat with a different name in each window and chat away

Also read...

Comments

  1. article is good just wondering why you gave example of sending message to yourself with such long way long like

    io.sockets.socket(clients.mheap.socket).emit();

    you could use

    socket.emit();

    to send message to yourself directly. Or is there anything wrong with this?

    Reply
    • It depends what context you’re in, and what the value of `socket` is. If you can guarantee that `socket` is the one you definitely want to write to, `socket.emit()` is fine. Personally, I prefer the lookup as it’s more explicit

      Reply
  2. Hi there!

    I´m just starting with socket.io and I was wondering why you didn´t use namespaces or rooms instead of what you explain on your post.

    Would we achieve the same result using rooms or namespaces that using your method? I guess yes.

    Thanks! btw good post :)

    Reply
  3. did not work with new version of socket.io?. I got an error at io.sockets.on(‘connection’, …) -> “Cannot call method ‘on’ of undefined”. I dont know why

    Reply

Leave a Reply