Adam Coffman

I write code, sometimes well.

Getting Your Feet Wet With node.js and socket.io - Part 1

| Comments

I haven’t had a ton of time to work on my node.js project lately so I figured I’d just put it out there in its current form as a learning tool for others. In this blog post I’ll walk you through everything I did to get it working and, by the end, you should be able to write your own basic webapps using socket.io.

First, let’s start with an overview of the functionality we’d like to have. We want a semi-real time news feed that can display messages passed in from one or more client applications. In order to tell which application passed in which message, we’d like to have some color coding as well. Since we’re using socket.io we also want to avoid AJAX callbacks in favor of server pushes. Finally - it would be cool to see a count of the number of other people also viewing the news feed.

For this project I’m going to use the Jade templating language, and the Express node.js framework, which provides Sinatra style routing for node applications. Links to each can be found in the project readme.

Lets start off by creating our app and setting it up to use Jade, socket.io, and Express.

1
2
3
4
5
6
var app = require('express').createServer();
var socket = require('socket.io').listen(app);

require('jade');
app.set('view engine', 'jade');
app.set('view options', {layout: false});

We need to import the Express library and call the createServer() method on it to get a server object. We’ll store it in app. Then we import the socket.io library and attatch it to listen on our newly created server. Finally we import the Jade library, set our app to use it as the view engine and configure some basic settings.

Now that we have the basic setup out of the way - lets set up our routes to serve both our main news feed page as well as any javascript or css we may need. If you’re familiar with Sinatra in Ruby and Javascript’s callback syntax - these will make perfect sense to you.

1
2
3
4
5
6
7
app.get('/*.(js|css)', function(req, res){
  res.sendfile("./public"+req.url);
});

app.get('/', function(req, res){
  res.render('index');
});

You’ll see that we match any GET requests for js and css files and pass them along to the “public” dir, which is where we will serve our static files from. Then we’ll take any root level requests and serve up our index view. As we have it written here, node will look for a file called index.jade in the “views” directory, run it through the Jade processor, and then render it out to the browser. At this point, we should probably take a quick look at the index view. There’s nothing complicated here, just a couple of lists and a couple of divs. I won’t go over the syntax of Jade, but it should be pretty self explanatory. We set up some script tags to include JQuery and socket.io from their respective CDNs and a local javascript file for our application specific code. Then we add a couple of lists for our news feed and a footer to display our connected client count.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
!!! 5
html(lang="en")
  head
      title nodeFeed
    link(rel="stylesheet", type="text/css", href="/main.css")
    script(type="text/javascript", src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js")
    script(type="text/javascript", src="http://cdn.socket.io/stable/socket.io.js")
    script(type="text/javascript", src="/feed.js")
  body
    #heading
      h1 News Feed
    #content
      #categories
        ul#category_list
      #feed
        ul#feed_list
    #footer
      p
        span#client_count 0
        |  connected clients

If we were to run the node server now, it would work, but it wouldn’t do anything - it would just render out our basically empty view. Not particularly useful. Now that we have the basic structure in place however, the fun can begin. Let’s get socket.io hooked up and talking to the clients. We’ll start by implementing a real-time count of connected clients. On the server side it will look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
var activeClients = 0;

socket.on('connection', function(client){
  activeClients +=1;
  socket.broadcast({clients:activeClients})
  client.on('disconnect', function(){clientDisconnect(client)});
});

function clientDisconnect(client){
  activeClients -=1;
  client.broadcast({clients:activeClients})
}

We will bind an anonymous function to the socket ‘connection’ event that will execute every time a new client connects. When this happens we will increment the current count of connected clients, and then send out a broadcast containing the count. The socket.broadcast method sends a message to all connected clients. In this case we’re passing some JSON that contains our count. We then use the same syntax to bind a function to execute when the client disconnects. This function simply decrements the count and broadcasts the count back to the remaining clients.

We’re all set on the server side but we need to set up some javascript on the client side to listen for the messages and update the view accordingly.

1
2
3
4
5
6
7
8
9
10
11
function msgReceived(msg){
  $clientCounter.html(msg.clients);
}

$(document).ready(function () {
  $clientCounter = $("#client_count")

  var socket = new io.Socket(null, {port: 3000});
  socket.connect();
  socket.on('message', function(msg){msgReceived(msg)});
});

This code will need to go in the feed.js file we linked from the main view. We’re using JQuery’s document ready function to set up our client side socket and cache the selector for the client count on our page. Node.js runs on port 3000 by default so that’s what we’ll enter here. We’ll then bind a function to execute on the socket’s ‘message’ event. This seems like overkill now as the function is only one line, we could just as easily declare it inline anonymously, but we’ll be building on it in the next step. For now we’ll just update the client count.

At this point we have a working app - you can start up node.js, navigate to localhost:3000 and see: 1 connected client. If you open the page in another tab, you’ll see the counter update to 2 on both pages. Likewise, it will decrement as you close tabs. So far we’ve seen how to set up a very simple node.js app, import the Jade, Express, and socket.io libraries, and pass messages from the server to the clients using “comet” style message pushes. Now that we have the basics down, we’ll work on our news feed in the next post.

Hope you found this helpful - if you want to skip ahead and see the ‘finished’ product you can take a look at the github repo, otherwise we’ll cover the rest in the next post.

Comments