Node.js Websocket Examples with Socket.io

What are Websockets?

Over the past few years, a new type of communication started to emerge on the web and in mobile apps, called websockets. This protocol has been long-awaited and was finally standardized by the IETF in 2011, paving the way for widespread use.

This new protocol opens up a much faster and more efficient line of communication to the client. Like HTTP, websockets run on top of a TCP connection, but they're much faster because we don't have to open a new connection for each time we want to send a message since the connection is kept alive for as long as the server or client wants.

Even better, since the connection never dies we finally have full-duplex communication available to us, meaning we can push data to the client instead of having to wait for them to ask for data from the server. This allows for data to be communicated back and forth, which is ideal for things like real-time chat applications, or even games.

How do Websockets Work?

At its core, a websocket is just a TCP connection that allows for full-duplex communication, meaning either side of the connection can send data to the other, even at the same time.

To establish this connection, the protocol actually initiates the handshake as a normal HTTP request, but then gets 'upgraded' using the upgrade request HTTP header, like this:

The server then sends back an HTTP 101 "Switching Protocols" response, acknowledging that the connection is going to be upgraded. Once the this connection has been made, it switches to a bidirectional binary protocol, at which point the application data can be sent.

All the protocol has to do to keep the connection open is send some ping/pong packets, which tells the other side that they're still there. To close the connection, a simple "close connection" packet is sent.

Some Websocket Examples

Of the many different websocket libraries for Node.js available to us, I chose to use socket.io throughout this article because it seems to be the most popular and is, in my opinion, the easiest to use. While each library has its own unique API, they also have many similarities since they're all built on top of the same protocol, so hopefully you'll be able to translate the code below to any library you want to use.

For the HTTP server, I'll be using Express, which is the most popular Node server out there. Keep in mind that you can also just use the plain http module if you don't need all of the features of Express. Although, since most applications will use Express, that's what we'll be using as well.

Note: Throughout these examples I have removed much of the boilerplate code, so some of this code won't work out of the box. In most cases you can refer to the first example to get the boilerplate code.

Establishing the Connection

In order for a connection to be established between the client and server, the server must do two things:

Hook in to the HTTP server to handle websocket connections

Serve up the socket.io.js client library as a static resource

In the code below, you can see item (1) being done on the 3rd line. Item (2) is done for you (by default) by the socket.io library and is served on the path /socket.io/socket.io.js. By default, all websocket connections and resources are served within the /socket.io path.

If you navigate your browser to http://localhost:8080 and inspect the HTTP requests behind the scenes using your browser's developer tools, you should be able to see the handshake being executed, including the GET requests and resulting HTTP 101 Switching Protocols response.

Sending Data from Server to Client

Okay, now on to some of the more interesting parts. In this example we'll be showing you the most common way to send data from the server to the client. In this case, we'll be sending a message to a channel, which can be subscribed to and received by the client. So, for example, a client application might be listening on the 'announcements' channel, which would contain notifications about system-wide events, like when a user joins a chat room.

On the server this is done by waiting for the new connection to be established, then by calling the socket.emit() method to send a message to all connected clients.

Counting Connected Users

This is a nice example to learn since it shows a few more features of socket.io (like the disconnect event), it's easy to implement, and it is applicable to many webapps. We'll be using the connection and disconnect events to count the number of active users on our site, and we'll update all users with the current count.

A much simpler way to track the user count on the server would be to just use this:

var numClients = io.sockets.clients().length;

But apparently there are some issues surrounding this, so you might have to keep track of the client count yourself.

Rooms and Namespaces

Chances are as your application grows in complexity, you'll need more customization with your websockets, like sending messages to a specific user or set of users. Or maybe you want need strict separation of logic between different parts of your app. This is where rooms and namespaces come in to play.

Note: These features are not part of the websocket protocol, but added on top by socket.io.

By default, socket.io uses the root namespace (/) to send and receive data. Programmatically, you can access this namespace via io.sockets, although many of its methods have shortcuts on io. So these two calls are equivalent:

Now any data sent within this namespace will be separate from the default / namespace, regardless of which channel is used.

Going even further, within each namespace you can join and leave 'rooms'. These rooms provide another layer of separation on top of namespaces, and since a client can only be added to a room on the server side, they also provide some extra security. So if you want to make sure users aren't snooping on certain data, you can use a room to hide it.

Then from there you can send messages to everyone belonging to the given room:

io.to('private-message-room').emit('some event');

And finally, call .leave() to stop getting event messages from a room:

socket.leave('private-message-room');

Conclusion

This is just one library that implements the websockets protocol, and there are many more out there, all with their own unique features and strengths. I'd advise trying out some of the others (like node-websockets) so you get a feel for what's out there.

Within just a few lines, you can create some pretty powerful applications, so I'm curious to see what you can come up with!

Have some cool ideas, or already created some apps using websockets? Let us know in the comments!