A sample chat application using Node.js and Socket.io

This entry is an attempt to demonstrate the use of Node.js and Socket.io in a sample web application. As we proceed with this, we will be developing a sample chat application.

Traditional approach

At the outset, web applications running inside a web browser are designed in such a way that the client (browser) initiates communication with the server. For instance, the browser:

indicates to the server that it is interested in accessing certain service (say, get stock quotes)

further tells the server what stock symbols it is interested in (say, IBM, MSFT etc)

receives the stock details from the server (such as price, percent change etc.)

recursively polls the server for the updated prices etc

So, there is a piece of code (such as Javascript) running in the browser constantly polling for further data from the server. Several improvements were made to streamline this approach with the introduction of AJAX, GWT etc. But, under the hood, the basic idea is still the same – client making requests to which the server responds.

Now

A different approach to addressing such requirements is to let the server push any data to the client(s) rather than having the clients “pulling” it. A few frameworks emerged lately to support this approach, one of which is WebSockets. In this write-up, I intend to walk through a simple chat application that uses this approach using node.js, socket.io and jQuery. Let’s start.

The requirement

We will be developing a chat application with the following abilities:

Users pick a name before they start chatting

A user can send a message to the whole room or a specific user

Installation/Setup

We need the following. Installing node.js should install “npm” as well by default. So, you can use “npm” to install the rest (express, socket.io and jade). For now, install only the node.js from the list below and proceed further.

What this did for us is created (among other files) the helpful package.json (which contains all the details of our application including any dependent modules). Now, do as it suggests (npm install). This gets and installs any dependent modules defined in package.json (which was generated by ‘express’).

$ npm install

And, fire up the server using this:

$ node app.js
Express server listening on port 3000

Looks good. Open a browser and point it to http://localhost:3000 and feel welcomed by Express which says:

Express
Welcome to Express

You can stop the server by hitting Ctrl-C in the command window.

What is going on under-the-hood?

How did we get that welcome page? Let’s try and understand that first. This will give us an idea of how jade and express organizes the folders, control flow etc. Open up app.js file. It should be under “sample1” folder.

Lines 5 through 9 indicate to node.js the different modules that will be used within this file. Essentially, the functions exposed by each of those modules are available via the variable used in these lines. For example, the variable “express” can be used to access any function(s) exposed (exported) by the “express” module mentioned as argument to the require() call.

Line 11 is where use one such variable “express”. To add to your understanding, if you were to rename the variable in line 5 from var express = ... to var superExpress = ..., then line 11 should look like var app = new superExpress().

Next few lines 13 – 27 configure the “app”.

Line 29 is what I am after. It specifies that when a client (browser) requests for the root (“/”), serve it “routes.index”. But, what is routes.index? To understand that, first see line 6. See that variable “routes”? That is pointing to the module “./routes”. In simple terms, this is nothing but a folder named “routes” in the current folder (which is “sample1”). Browse to that folder and open up index.js. In there, you will find this:

See the line 5 with “exports.index”? The “.index” makes it expose (or export) a certain function as a name “index”. So, whoever uses this module will be able to call this exposed function using the name “index”.

So, when routes.index() is called at line 29 in app.js, this is the function that gets called. What is this function doing? Well, it is calling res.render() and passing it ‘index’. In other words it is rendering a page represented by “index”. By default, it uses jade and the jade files are under “sample1/views” folder. You should find a file named “index.jade” which corresponds to the first argument “index” passed to res.render(). Let’s open up index.jade and see what is in there. You will find “Welcome to #{title}” in there. And, the “title” is passed to it when we called “res.render()” above. That covers the end-to-end call of the page is rendered.

We can take it even further for a better understanding. Edit sample1/routes/index.js and change the contents to the following:

Now, start the server back up using “node app.js” and visit localhost:3000. Do you see your changes?

Let’s get to the real coding

Now, that we have the required modules installed, let’s begin the fun part. We are going to a develop a simple chat application that let’s users logon and send messages across to the connected clients. Here is a simple depiction of that:

Basic UI

Let’s have the basic UI in place. Before we get started on that, you will need the jQuery library. Get the “jquery-1.7.2.min.js” from this link and save a copy under “sample1/public/javascripts/jquery” folder (Create the “jquery” folder under “javascripts” folder if needed). Now, move on to edit “sample1/views/layout.jade” and change the contents to the following:

Let’s go and use this in our app.js. Edit “sample1/app.js” and a require() for chat. Also, add require() for socket.io. We will be needing it shortly. So, the top section will have something like this:

Now, on the client side, we need the code listening to the events coming from the server such as “userJoined”, “userLeft”, “welcome” and “error”. Above, we have seen that chat.jade has a reference to “/javascripts/chat.js”. The client side code goes into this script. Create or edit this file (“sample1/public/javascripts/chat.js”) with the following content:

Save all and start/restart the server. Browse to http://localhost:3000/chat. Start with entering a user name. Open multiple browser windows/tabs each with a different user name and chat away and see how the messages get relayed.

Like this:

38 Responses to A sample chat application using Node.js and Socket.io

It’s not working. in console window, it looks like the app is requesting from localhosthttp://localhost:3000/socket.io/1/?t=1351106826018
in public/javascripts/chat.js,
i’m trying to change socket = io.connect(“http://localhost:3000”); to my public ip but not working too. Am i missing something? anyway good tutorial.

Where is this app deployed/hosted? To have your client point to socket.io on your host, you could change this line
socket = io.connect(“http://localhost:3000”);
to
var socket = io.connect(document.location);

Same here, just downloaded the source code from git hub and started the application. As soon as i access the localhost:3000/chat url i get this error
PS C:\…\sample1> node .\app.js
info – socket.io started
Express server listening on port 3000
GET /chat 200 36ms – 686

http.js:707
throw new Error(‘Can\’t set headers after they are sent.’);
^
Error: Can’t set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:707:11)
at ServerResponse.res.setHeader (C:\…\sample1\node_modules\express\node_modules\co
nnect\lib\patch.js:59:22)
at next (C:\…\sample1\node_modules\express\node_modules\connect\lib\proto.js:153:1
3)
at Function.app.handle (C:\…\sample1\node_modules\express\node_modules\connect\lib
\proto.js:198:3)
at Server.app (C:\…\sample1\node_modules\express\node_modules\connect\lib\connect.
js:66:31)
at Manager.handleRequest (C:\…\sample1\node_modules\socket.io\lib\manager.js:564:2
8)
at Server. (C:\…\sample1\node_modules\socket.io\lib\manager.js:118:10)
at Server.EventEmitter.emit (events.js:117:20)
at HTTPParser.parser.onIncoming (http.js:2056:12)
at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:120:23)
PS C:\…\sample1>

I am getting the following error
d:\tools\sample1\routes\chat.js:35
socket = io.connect(document.location);
^
ReferenceError: io is not defined
at Object. (d:\tools\sample1\routes\chat.
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.require (module.js:362:17)
at require (module.js:378:17)
at Object. (d:\tools\sample1\app.js:12:12
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)

Why do you use a timeout of 500 on the server side before sending a response? It seems to work just as well with a value of 10, or even without using a timeout at all. I think I understand the reasoning behind using a timeout for asynchronous flow, but is there really a need for such a long delay?

I have resolved proxy problem and now I am able to join the chat. I am getting the message “Username available. You can begin chatting.” but after that, nothing is editable. And on command prompt following messages are shown:

Hi, thanks a lot for this tutorial, I’ve beeen reading some tutorials and this one is the best!

I have a doubt about node: I don’t understand where it has to be installed, and if once installed in one folder do I need to install it in every folder app?
What happen if I want to start another app? Do I need to create another folder and install express, jade,.. again or is there a way to install all globally?

http.js:691
throw new Error(‘Can\’t set headers after they are sent.’);
^
Error: Can’t set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:691:11)
at ServerResponse.res.setHeader (C:\Users\mark\Downloads\chat-master\node_modules\express\node_modules\connect\lib\patch.js:59:22)
at next (C:\Users\mark\Downloads\chat-master\node_modules\express\node_modules\connect\lib\proto.js:153:13)
at Function.app.handle (C:\Users\mark\Downloads\chat-master\node_modules\express\node_modules\connect\lib\proto.js:198:3)
at Server.app (C:\Users\mark\Downloads\chat-master\node_modules\express\node_modules\connect\lib\connect.js:66:31)
at Manager.handleRequest (C:\Users\mark\Downloads\chat-master\node_modules\socket.io\lib\manager.js:564:28)
at Server. (C:\Users\mark\Downloads\chat-master\node_modules\socket.io\lib\manager.js:118:10)
at Server.EventEmitter.emit (events.js:117:20)
at HTTPParser.parser.onIncoming (http.js:2108:12)
at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:121:23)
7 Jan 15:46:03 – [nodemon] app crashed – waiting for file changes before starting…

at Object.Lexer.doctype (/home/prathap/sample1/node_modules/jade/lib/lexer.js:252:13)
at Object.Lexer.next (/home/prathap/sample1/node_modules/jade/lib/lexer.js:833:15)
at Object.Lexer.lookahead (/home/prathap/sample1/node_modules/jade/lib/lexer.js:113:46)
at Parser.lookahead (/home/prathap/sample1/node_modules/jade/lib/parser.js:111:23)
at Parser.peek (/home/prathap/sample1/node_modules/jade/lib/parser.js:88:17)
at Parser.parse (/home/prathap/sample1/node_modules/jade/lib/parser.js:126:26)
at Parser.parse (/home/prathap/sample1/node_modules/jade/lib/parser.js:140:24)
at parse (/home/prathap/sample1/node_modules/jade/lib/jade.js:95:62)
at Object.exports.compile (/home/prathap/sample1/node_modules/jade/lib/jade.js:152:9)
at Object.exports.render (/home/prathap/sample1/node_modules/jade/lib/jade.js:256:15)

Great post and easy to follow.I have the chat up and running but I notice that once I post a chat it does not appear in the chat message board.How can I enable to view my chat messages.
Secondly how can I integrate a notification script.