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 [email protected]: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

Michael is a polyglot software engineer, committed to reducing complexity in systems and making them more predictable. Working with a variety of languages and tools, he shares his technical expertise to audiences all around the world at user groups and conferences. You can follow @mheap on Twitter

Thoughts on this post

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?

michael 2014-01-31

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

zot24 2014-03-02

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 🙂

michael 2014-03-08

I’m not sure rooms existed when I wrote this post. Nowadays, I’d definitely be using rooms 🙂

I will be using rooms in my WebRTC project, for chat and an abstract channel for signaling. Even with rooms, knowing how to create rooms, I want to use those as ‘actual’ rooms (ie: not just 2 clients(usually)) therefore, and my point is…. I still found this part on sending to a specific socket extremely useful, its precisely what i was googling for.

The reason I still need this even with namespaces, is I am using it for RTC video Signaling as well as chat on(“chat message”) vs on(“vChatInvite”) etc..

Currently, every client joins the default namespace, which I am calling the ‘lobby’ but If they want to video chat each other, I want them to be able to do it without even myself (or especially the user) worrying about what room they are in, or putting them in a different room before starting the signaling. Therefore I needed a way in a room with Alice, bob, Jim and Gilbert for Alice to chat with jim and gilbert while dancing for tips with bob. Its actually for an educational site but you get the idea. Long story short… THANKS for this useful info, even with rooms, its needed.

Chuối Cụ 2014-06-18

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

michael 2014-06-26

I’ve updated the post. You need to change io.sockets.socket to io.sockets.connected

(with thanks to gs-akhan – https://github.com/gs-akhan/socketio-chat-example/commit/7439fbd27b6b4e202227b76a814101ef8cadec6d)

Fabio 2014-07-20

Great post man. I’m from Brazil and I’m starting with socket.io and i have a question. When the browser refreshes, the socket is removed and a new socket is created. Is there no problem with this?

michael 2014-08-04

Yeah, you need to maintain an array of socket ID’s. I’d just use the rooms functionality now though.

Andre Linoge 2014-08-16

Hello Michael. Thank you for your post – it is very useful. It’ll be great if you write a post about using rooms functionality or even rewrite this chat application with using of rooms.

Thanks!

atomxml 2014-09-29

Thank you.

elghazal 2014-09-30

Hey there, thanks for your article.
connected is not a function, it’s an associative array.
io.sockets.connected[clients.mheap.socket].emit()

michael 2014-10-13

Updated, thanks

Igor Vujovic 2015-04-16

Now you can add metadata to a socket connection on connect (without using socket.auth and a session)
Client:
iosocket = io.connect(‘//Host:Port/NameSpaceorBlank’, {query: ‘param1=1245&param2=something’} );

on Server you can read params from
socket.handshake.query object

Nikunj Chapagain 2015-11-17

I kept thinking heap was some sort of data structure you were referring to.Only to find out that it was your last name. Haha.. Great article, helped me so much on my WebRTC project. Thank You so much.

Dan 2017-05-04

How would this scale across multiple server instances?

michael 2017-05-04

I’m afraid it wouldn’t

toshinorix 2017-06-09

Thank You for this simple solution.

Leave a comment?

Leave a Reply