Let's Chat

Rohit Rai

March 2013

(For more resources related to this topic, see here.)

Creating the application

We will create our application, which will be called awesome-chat, by executing the following commands in the Node.js command line:

$ express awesome-chat $ cd awesome-chat $ npm install

This will create our application and install the express application dependencies. Open the package.json file and change the name to awesome-chat, as shown in the following code snippet:

{ "name": "awesome-chat", "version": "0.0.1", "private": true, "scripts": { "start": "node app" }, "dependencies": { "express": "3.0.0rc2express": "3.x", "jade": "*" } }

Designing the chat room

Let's modify the view to make it look like a chat room. We will need an area to display the messages, a text input for the user to enter the message, and a button to send the message. We will add some aesthetic elements, such as a header, banner, and footer. When we are done, our chat room user interface should look like the one shown in the following screenshot:

Awesome chat UI

Let's start editing layout.jade by adding a header and footer to it:

doctype 5 html block head title= title link(rel='stylesheet', href='/stylesheets/style.css') body header#banner h1 Awesome Chat block content footer Hope you enjoy your stay here

The first change we make is to add the block keyword before head. This makes head a block, to which we can append content from the extending pages.

The other change is the addition of a new header and footer. Note that we are using the header and footer tags from HTML5. This code also introduces us to a new jade syntax. When we write header#banner , it will generate headers with banner as the id value. The generated HTML code will be as follows:

<!DOCTYPE html> <html> <head> <title>{TITLE}</title> <link rel="stylesheet" href="/stylesheets/style.css" /> </head> <body> <header id="banner"> <h1>Awesome Chat</h1> </header> {CONTENT} <footer> Hope you enjoy your stay here </footer> </body> </html>

Next, we will edit index.jade to add the message area, message input, and the Send button:

extends layout block content section#chatroom div#messages input#message(type='text', placeholder='Enter your message here') input#send(type='button', value='Send')

Let's run and see what our awesome-chat application looks like. Execute the application using npm and open http://localhost:3000/ in the browser:

npm start

Hey, all the elements are there, but it doesn't look right! That's correct; to improve the look and feel of the application, we need to edit the stylesheet, which is located at public/stylesheets/style.css.

We can edit it according to our taste. Here is one that works just fine for me:

html { height: 100%; } body { font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; margin: 0px; padding: 0px; height: -moz-calc(100% - 20px); height: -webkit-calc(100% - 20px); height: calc(100% - 20px); } section#chatroom { height: -moz-calc(100% - 80px); height: -webkit-calc(100% - 80px); height: calc(100% - 80px); background-color: #EFFFEC; } div#messages { height: -moz-calc(100% - 35px); height: -webkit-calc(100% - 35px); height: calc(100% - 35px); padding: 10px; -moz-box-sizing:border-box; -webkit-box-sizing:border-box; box-sizing:border-box; } input#message { width: -moz-calc(100% - 80px); width: -webkit-calc(100% - 80px); width: calc(100% - 80px); } input#send { width: 74px; } header{ background-color:#4192C1; text-align: right; margin-top: 15px; } header h1{ padding: 5px; padding-right: 15px; color: #FFFFFF; margin: 0px; } footer{ padding: 6px; background-color:#4192C1; color: #FFFFFF; bottom: 0; position: absolute; width: 100%; margin: 0px; margin-bottom: 10px; -moz-box-sizing:border-box; -webkit-box-sizing:border-box; box-sizing:border-box; } a { color: #00B7FF; }

After saving this CSS and refreshing the page, here is what the chat room looks like:

The awesome chat room

Bringing in jQuery

jQuery is almost ubiquitous when it comes to JavaScript libraries, and we will use it in our application too. To add jQuery to our application, let's download the latest release from http://www.jquery.com/ and save it to public/javascript/jquery.min.js . Then, we add the script in layout.jade to pull in jQuery to our application's pages:

script(type='text/javascript', src = '/javascripts/jquery.min.js')


Ever since the onset of web applications, developers have worked towards different ways of getting duplex communication between the server and the browser. Be it using Java, Flash, Comet, or many other workarounds, all aim to do the same. But for the first time, there is a specification to build a full-duplex communication system by using HTML5 WebSockets. WebSocket is a revolutionary, new communication feature in the HTML5 specification that defines a full-duplex communication channel operating over the Web through a single socket.

Although the WebSockets RFC is published, it is not, and will never be, available on older browsers that are still in use. Socket.io is an abstraction layer for WebSockets, with Flash, XHR, JSONP, and HTMLFile fallbacks. Socket.io provides an easy server and client library for making real-time, streaming updates between a web server and a browser client.

Socket.io is a node module available through the npm, and we will add it to our package dependencies. The current release of socket.io is 0.9.10. To add this to our dependencies, add the following line to the dependencies object in package.json:

"socket.io": "0.9.10"

And install it using the npm:

$ npm install

This will bring socket.io in the node_modules folder. Now let's see how we will use it.

Handling events

Since the socket.io framework has components for both the server and the client, we will use these components to code our communication on both the sides. Events emitted on a socket on one side will be handled by the corresponding event handler on the other side. Socket.io is built so that both the sides can send messages or attach handlers to process the incoming messages.

Let's begin by understanding how the messages will flow. It is important to remember that "messages" here are not the actual messages sent and received by users of the chat system, but the messages used for communication by the client and the server. There will be two types of messages, as follows:

  • The system messages: These messages will be sent by our chat system to the client, like when the user is connected, when others connect, or when users disconnect. Let's identify it with serverMessage.

  • The user messages: These messages will be sent by the client to the server and will actually carry the user's message content in the payload. We will probably want to differentiate between the messages we send and the messages other users send. So let's call them myMessage and userMessage respectively.

When a user connects for the first time, the server will send a welcome message to the user as a serverMessage message.

When a user types in a message and presses the Send button, we will send a userMessage message from the browser to the server.

On receiving the user message, the server will broadcast this message to all the other users. It will also send back the same message as myMessage to the user who originally sent the message.

On receiving any message from the server, the browser will display the contents of the message in the message area.

The server

Now we will implement the server, which will perform the task of relaying the messages, as already mentioned. Create a file in the routes folder called sockets.js and insert the following code into it:

var io = require('socket.io'); exports.initialize = function(server) { io = io.listen(server); io.sockets.on("connection", function(socket){ socket.send(JSON.stringify( {type:'serverMessage', message: 'Welcome to the most interesting chat room on earth!'})); socket.on('message', function(message){ message= JSON.parse(message); if(message.type == "userMessage"){ socket.broadcast.send(JSON.stringify(message)); message.type = "myMessage"; socket.send(JSON.stringify(message)); } }); }); };

In the first line of code (you must be familiar with this by now), we import the socket.io module; we will identify this module by the io variable.

Since socket.io works with the communication layer, we need to set it up to listen to the HTTP server. The HTTP server can only be accessed from the main application module, so we have to pass server to our module before our module can do anything. Hence, we export a method called initialize from our module, which will set up the socket.io server and also bind all the message handlers:

exports.initialize = function(server) { //work to do }

The initialize method will accept the HTTP server object as a parameter. This is required by socket.io:

io = io.listen(server);

On the first line of the method, we will pass the server to the socket.io module's listen method. The server is an instance of the node HTTP server module; socket.io will configure various handlers on this server. This is the only boilerplate code required to set up socket.io. Next, we need to set up our message handler for socket. io messages.

The first event that our server will receive is a new connection from a new client. This is identified by the connection event on the io.sockets object and notifies our application that a new client has opened a new connection and all the protocol negotiation (transparent to us) has been completed and now we have a socket to communicate with this client:

io.sockets.on("connection", function(socket){ //Add other event handlers to the socket });

The connection event handler will be triggered, passing along the socket that was just established. The socket is an event emitter that can trigger different events based on the messages it gets, and we will use this socket also to communicate with the client for which it was created. There are several events exposed, such as the connection event to handle events on the server. Let's take a quick look at these events:

  • io.sockets.on('connection', function(socket) {}): Initial connection from a client. The socket argument should be used in further communication with the client.

  • socket.on('message', function(message, callback) {}): The message handler is triggered when a message sent with socket.send is received. The message parameter is the message sent, and callback is an optional acknowledgment function.

  • socket.on('anything', function(data) {}): The anything event can be any event except the reserved events.

  • socket.on('disconnect', function() {}): This event is fired when the socket disconnects.

Now that we have seen how to handle the socket events, let's see how we can send messages from the server to the client:

socket.send(JSON.stringify( {type:'serverMessage', message: 'Welcome to the most interesting chat room on earth!'}));

The socket.send method will send the message on the socket, which will be triggering the message event on the client. The message sent has to be a string, so we will use JSON.stringify to send the data for the message as a string. Here our message has two parts, a type and a message.

One part of our task is over, we are now able to welcome the user. The next task is to handle the user messages when they come in. For this, we set a message event handler on the socket:

socket.on('message', function(message){ message= JSON.parse(message); if(message.type == "userMessage"){ socket.broadcast.send(JSON.stringify(message)); message.type = "myMessage"; socket.send(JSON.stringify(message)); } });

Just like any other event connector, socket.on will take two parameters, namely the event to handle and the event handler for it. In this case, unlike the io.sockets.on event, this event handler will receive the message as the parameter and not the socket.

Since the message is a string, we will parse the message's JSON string to create a message object. If this is a message sent by the user, this message will be of the type userMessage, and that is what we check.

Now, we have to send out this message to all the connected users. For this, socket.io provides us with a broadcast object. When we send the message using the broadcast object, it will be sent to all the clients that are connected, except to the one for which this socket was created. The syntax for sending the message here is the same; the difference is that it is called on the broadcast object, referred to as message flags in socket.io, instead of the socket itself.

Also, we want to send back the same content to the client that sent this message, but just change the type to myMessage. For this, we send the message directly on the socket.

That's it. We have written the code for the server; but now we have to actually initialize this server. To do this, modify the server creation in app.js to set the server variable, as shown in the following code snippet:

var server = http.createServer(app).listen(app.get('port'), function(){ console.log("Express server listening on port " + app. get('port')); });

Now that we have modified the HTTP server, we can call the socket module's initialize method, passing this server as a parameter to it. Add the following line to the end of app.js:


The client

Now that we have seen how the server works, let's see what the client does. The best part of socket.io is that it provides us the same API on the server and the client. For our chat logic on the client, let's create a file called chat.js in the public/javascripts folder and add the following code to it:

var socket = io.connect('/'); socket.on('message', function (data) { data = JSON.parse(data); $('#messages').append('<div class="'+data.type+'">' + data.message + '</div>'); }); $(function(){ $('#send').click(function(){ var data = { message: $('#message').val(), type:'userMessage' }; socket.send(JSON.stringify(data)); $('#message').val(''); }); });

The first step in starting the chat is to connect to the server:

var socket = io.connect('/');

This will send a connection request to the server from which the page was loaded. This will also negotiate the actual transport protocol and will finally result in the connection event being triggered on the server app.

The following code snippet connects the event handler for the message event:

socket.on('message', function (data) { data = JSON.parse(data); $('#messages').append('<div class="'+data.type+'">' + data.message + '</div>'); });

All we have to do with the incoming message is to append it to the messages area. We are adding one additional detail here by setting the class property for the newly appended div tag to be of the same type as that of the message. We can later use this to give a different look to the different types of messages.

The last thing to do on the client side is to send the messages from the user. This will be done when the user writes his/her message in the message box and clicks the Send button. So, let's add an event handler to the Send button. The important thing about UI elements' event handlers is that they should be attached once the element is added to the document, that is, after it is created and ready. jQuery provides a convenient method to detect when the document is ready and adds a handler function to execute. There are two ways to do this; one is the following:

$(document).ready(function(){ //Execute once the document is ready });

The shortcut for the same is as follows:

$(function(){ //Execute once the document is ready });

Once the document is ready, we attach the event handler to the click event of the Send button:

$(function(){ $('#send').click(function(){ var data = { message: $('#message').val(), type:'userMessage' }; socket.send(JSON.stringify(data)); $('#message').val(''); }); });

On clicking the Send button, we create our data object, setting the content of the message box as message, and type as userMessage. We can then use the socket.send method to send this data to the server. As you can see from the preceding code snippet, the syntax for sending messages from the client is the same as that of the server, and here too the message will be sent as a sting, which we create using JSON.stringify(data).

Like the connection event and other predefined events on the server, we have some predefined events on the client too. These are as follows:

  • socket.on('connect', function () {}): The connect event is emitted when the socket is connected successfully.

  • socket.on('connecting', function () {}):The connecting event is emitted when the socket is attempting to connect with the server.

  • socket.on('disconnect', function () {}): The disconnect event is emitted when the socket is disconnected.

  • socket.on('connect_failed', function () {}): The connect_failed event is emitted when socket.io fails to establish a connection to the server and has no more transports to fall back to.

  • socket.on('error', function () {}): The error event is emitted when an error occurs and it cannot be handled by the other event types.

  • socket.on('message', function (message, callback) {}): The message event is emitted when a message sent by using socket.send is received. The message parameter is the sent message, and callback is an optional acknowledgment function.

  • socket.on('anything', function(data, callback) {}): The anything event can be any event except the reserved events. The data parameter represents the data, and callback can be used to send a reply.

  • socket.on('reconnect_failed', function () {}): The reconnect_ failed event is emitted when socket.io fails to reestablish a working connection after the connection was dropped.

  • socket.on('reconnect', function () {}): The reconnect event is emitted when socket.io is successfully reconnected to the server.

  • socket.on('reconnecting', function () {}): The reconnecting event is emitted when the socket is attempting to reconnect with the server.

The last task to be done on the client side is to add socket.io and the chat scripts to our chat room page. Since these will not be used on every page, instead of adding them to layout.jade, we will add these to index.jade.

Remember the change we had made to layout.jade, changing the code from head to block head? It will allow us to append the content from index.jade to the head tag:

block append head script(type='text/javascript', src = '/socket.io/socket.io.js') script(type='text/javascript', src = '/javascripts/chat.js')

In the following line of code, we are using Jade's functionality to append content to a block in an inherited template from the child element. This is done using the append keyword. The syntax is as follows:

block append <blockname>

The shorter form is as follows:

append <blockname>

The next two lines of code add the script tags by adding socket.io.js and chat. js to our page. You might be wondering where the /socket.io/socket.io.js file comes from, since we neither add it and nor does it exist on the filesystem. This is part of the magic done by io.listen on the server. It creates a handler on the server to serve the socket.io.js script file.

And we are ready. Restart the node server and browse to http://localhost:3000/ to open the chat room. You will see the welcome message, Welcome to the most interesting chat room on earth!, being displayed in the message area.

To see how our chat application works, open it in two separate browser instances. Now you can enter your message in the message box in one of the browsers and click Send. You will see it appear on the message area of both the browsers.

Congratulations! We now have a chat room. If you deploy it to a server or allow access to port 3000 on your system, you can invite your friends to chat.


In this article, we learned about socket.io and worked through some very basic concepts and APIs provided by socket.io. We also saw how to set up socket.io on the server and the client, and how to send and receive messages. While doing so, we also built a chat room application using all that we had learned.

You can also build upon the application that we have created to add other features such as session data, multiple chat rooms, namespacing, and authentication and in the bargain, get acquainted with the related features of socket.io.

Resources for Article :

Further resources on this subject:

You've been reading an excerpt of:

Socket.IO Real-time Web Application Development

Explore Title