Zack Hobson

Node.js and HTML5 Web Sockets Sunday March 28, 2010

Web Sockets elevate socket networking in client-side web apps to a first-class citizen, giving clients and servers a simple way to communicate over a persistent stream without the need for third-party plugins or hacks. Now that the developer release of Chrome supports Web Sockets, I decided to give it a try using node. Having never touched this technology before, it took me most of a day to get it all working. I am writing up some notes on the process for others who might want to try out something similar.

One major caveat: Node’s networking code is in flux right now and which version you use can matter a great deal. For this exercise I’m using 0.1.33. It’s worth noting that I had to downgrade from the edge version of node to get this working.

The Server

Besides node itself, there is a module called node.ws.js that wraps node’s tcp socket API with a nearly identical interface: createServer() accepts a callback, and this callback receives an event listener for processing web socket events. Once a connection is made you can write to it like any socket. Messages from the client are processed asynchronously in the “data” listener.

var sys = require('sys'),
     ws = require('ws')

var server = ws.createServer(function (socket) {

  socket.addListener("connect", function (resource) {
    sys.puts("client connected from " + resource)
    socket.write("welcome\r\n")
  })

  socket.addListener("data", function (data) {
    socket.write(data)
  })

  socket.addListener("close", function () {
    sys.puts("client left")
  })
})

server.listen(8080)

Communication is initiated from the web browser with a special handshake sequence. This sequence looks like an HTTP header and is designed to allow an existing HTTP connection to upgrade to a web socket. We won’t be taking advantage of this functionality, but there is a project called Socket.IO that provides some compelling features in this regard and may be worth a look.

The Client

Remember that in order for this to work your web browser must support web sockets, which is fairly rare at the moment. You will probably need to run a development version of Google Chrome.

Conceptually the client and server are nearly identical, as they’re both reading and writing asynchronously to a network socket. In the client it’s trivial to hook these callbacks up to the DOM using jQuery to do stuff like display server messages on the page.

I did quite a bit of digging before I stumbled on this great jQuery plugin called ws. The actual WebSocket API is quite easy to use, but I was going to be using jQuery in my client anyway, so why not. Certainly, the API for this plugin is pleasantly concise:

$(document).ready(function () {
  var ws = $.ws.conn({
    url : 'ws://localhost:8080',

    onopen : function () {
      console.log('connected');
    },

    onmessage : function (data) {
      console.log("received: " + data)
    },

    onclose : function (event) {
      console.log('disconnected');
    }
  });
});

This is pretty much the simplest possible thing you can do, but I hope this minimal example illustrates the potential of this technique. This works in the latest developer builds of Chromium or Google Chrome.

There are already some great examples of this kind of stuff in action. I recommend checking out this cool web socket demo from the developer of the ws jQuery plugin mentioned above. And of course there’s WPilot, which ties web sockets together with the awesome HTML 5 canvas element.