Under the hood of Socket.IO namespaces


I am working on a very simple game using NodeJS and Socket.IO. I decided to separate my game and chat communication into two namespaces in Socket.IO to make the logic a bit easier to follow. One problem I encountered was that I wasn’t sure how to broadcast to all connected clients in a specific namespace. If you’re not dealing with namespaces, it’s simple:

io.sockets.emit(...);

But what do you do with namespaces? I tried io.sockets.emit(...) as well as io.of('/chat').sockets.emit(), but neither of these attempts were successful. The documentation on the Socket.IO site also provided no clues.

While debugging my application, I decided to look into the source of Socket.IO. It’s actually pretty interesting to see some of the code behind how Socket.IO is implemented. I’ll go through a small sample of my code and explain what was going on behind the scenes. If you’re simply interested in the solution, feel free to skip to the bottom.

A very simplified version of some of my server code looks something like the following:

var express = require('express'),
    app = express.createServer().listen(8000),
    io = require('socket.io').listen(app),
    gameSocket = io.of('/game'),
    chatSocket = io.of('/chat');

Let’s break this down line by line.

var express = require('express'),
    app = express.createServer().listen(8000),
    io = require('socket.io').listen(app),
    gameSocket = io.of('/game'),
    chatSocket = io.of('/chat');

Nothing surprising here. I import the Express module, which is the web framework I am using.

app = express.createServer().listen(8000),

This line creates my Express web application. Since the focus of this post is Socket.IO, I don’t show the routes that I set up here, but there are plenty of examples at http://www.expressjs.com.

io = require('socket.io').listen(app),

There are two ways to create an instance of Socket.IO. The first is to allow it to create a native Node http server for you. If you call the listen() method on it without any arguments, it will default to a server listening on port 80. Otherwise, the server will listen on the port you specify.

The second way is to pass it an existing server. This is the way in which I’ve created my socket instance in the code example above, and probably the much more common usage of the library. Express is the example web server used in the Socket.IO documentation, but it would be interesting to see if it works just as well with other more obscure Node frameworks.

So what actually gets stored into the io variable? The call to listen() creates a Manager object, which manages a lot of the interaction with clients, including exchanging handshakes, generating sessionIds, and listening for heartbeats to detect when a client has disconnected. I did not spend too much time looking into these areas, however, since the part of Socket.IO that I was particularly interested in was the creation of namespaces.

gameSocket = io.of('/game'),
chatSocket = io.of('/chat');

This is where things get interesting. Remember that io is a Manager object. The of method takes a single string argument and creates a SocketNamespace object under that string or returns an existing one if it finds one.

The SocketNamespace object inherits from Node’s EventEmitter. Each client that connects to Socket.IO gets added as an event listener for the particular namespace through which the client is connected. Then, when the SocketNamespace needs to broadcast to all of its clients (or listeners), it emits the event and the clients’ event handlers are invoked. That is a 50,000 foot view of how Socket.IO works!

What happens if Socket.IO is used without any namespaces? If no namespace is specified:

// io.sockets is a SocketNamespace object
io.sockets.on('connection', function () {
  ...
});

then Socket.IO defaults to the empty string namespace, ''. The following would be equivalent to the previous code snippet:

// for the general namespace:
io.sockets.emit('newPlayer', playerName);
// or for a specific namespace:
io.of('/chat').emit('newPlayer', playerName);

After understanding what objects are being returned, I was able to figure out how to broadcast to all clients in a namespace:

// for the general namespace:
io.sockets.emit('newPlayer', playerName);
// or for a specific namespace:
io.of('/chat').emit('newPlayer', playerName);
This has been a very interesting experience in digging through the Socket.IO source. While I barely scratched the surface of this very useful module, the exposure to the source code has been more than enough to solidify my understanding of Socket.IO namespaces.
Copy from http://www.gordonkoo.com/
Advertisements

One comment on “Under the hood of Socket.IO namespaces

  1. I’m truly enjoying the design and layout of your blog.
    It’s a very easy on the eyes which makes it much more pleasant for me to come here and visit more often. Did you hire out a designer to create your theme?
    Excellent work!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s