The Complete Magazine on Open Source

Develop Real-time Applications with WebSockets and Socket.IO, Using Node.js

and
7.47K 0

nodejs

WebSockets is really useful for big applications, and your clients will definitely be impressed with the blazing speed it provides. Over time, it has improved considerably and got more stable. We might see a lot of scope for this technology very soon.

Real-time applications are those for which there is an instant response to a user request. Examples include your phone ringing when another person is calling you, or you receiving a text message from others, or even your MP3 player (in a way) using a real-time mechanism when you rock it to switch songs, forward or backward.

How do real-time applications work? First, let’s discuss real-time Web applications only, as real-time systems are very complex and hard to describe.

Polling
Polling is the simplest real-time application mechanism. The mechanism operates as follows: after every regular interval, a request is sent to the server to check for updates in the form of a vote; the server then checks for any updates and sends an up-vote if updates are available and if not, it replies with a down-vote. At the user end, if the server casts an up-vote, the system further asks for the updated data which is then passed by the server. Once this process completes, again, requests are sent to the server at the regular intervals.

Ajax is preferred for polling as it is lightweight and can update parts of the page without refreshing the entire page. The problem is with the bandwidth, of which a large amount is used by both the server and the client. To reduce this, a method called long-polling has been introduced, whereby an HTTP request stays up until a new message is sent by the server. Gmail Chat is an example of this mechanism.

WebSockets
Some applications need very little or almost no latency in client-server communication. This is only possible when there is persistent communication between the browser and the server, as it works in a bi-directional communication between the server and the client. Eventually, you can perform all the polling tasks by using WebSockets with minimum latency. Another great feature that WebSockets allows is browser-to-browser communication. This means that two client browsers can communicate with each other without any latency, while the server processes and stores data.

Applications of WebSockets
WebSockets has become quite popular among Web developers these days, and can be used for the following applications:

  • Chat application: Video and audio conferencing applications
  • Multi-player online gaming
  • Social feeds
  • Simultaneous file sharing

There are endless applications that can be built with WebSockets, like stock market monitoring, sports updates, an online broadcast, etc. The question is how to use them? There are two incredibly great JavaScript libraries, namely, HTML5Rocks and Socket.IO. HTML5Rocks is natively available in modern browsers, while Socket.IO boasts of being the fastest among the competition. We personally prefer using Socket.IO, as it is really good and compatible with most of the mobile and desktop browsers used by people today. It is also based on Node.js and thus is very reliable for backend functionality too.

figure-1-long-polling-via-ajax

Figure 1: Long polling via AJAX

An introduction to Socket.IO 
As discussed earlier, Socket.IO is a JavaScript library used to build real-time applications. We personally prefer it as it is nearly platform-independent — the applications tend to function across all the browsers without hiccups. Another reason is that Node.js has a great, lightweight JavaScript library to perform back-end functions.
Socket.IO boasts of being ‘the fastest and most reliable real-time engine’. Installing it is really simple.
So let us start by installing Socket.IO in your project. At present, there is just one way to install it — through npm (node package manager). For that, you have to open up your terminal and type the following command (you need to have Node.js installed on your machine):

$ cd /path/to/project_dir 
$ npm install socket.io

Getting started 
Before we start on this, you are required to at least have some knowledge of the fundamentals of Node.js. Let us create a project named test for which we need the following:

  • A computer/laptop with Windows, Linux or Mac installed with Node.js
  • A text-editor like Notepad++, Emacs, Atom, Sublime, etc.
    Create a project folder named test on your desktop (or wherever you prefer).

As the Socket.IO application is made using Node.js, the first and most important rule is to create a package.json file in the test folder with the following code:

{
            “name”:”test_application”,
            “version”:”0.0.1”,
            “private”:”true”,
            “dependencies”:{
                        “socket.io”:”1.4.8”,
                        “express”:”4.14.0”
            }  }

Now, open your terminal/cmd and use the following commands:

$ cd /path/to/project_dir
$ npm install

After the process completes, browse the project folder (test) and you will find a node_modules directory. Open it and you will see the Socket.IO and Express directories there.
Now, make a new file named test.js and write the following code in it:

var express = require(‘express’),
    test = express(),
    server = require(‘http’).createServer(test),
    io = require(‘socket.io’).listen(server);
server.listen(3000);
test.get(‘/’, function(req, res){
  res.sendFile(__dirname + ‘/welcome.html’);
});
 
 
io.sockets.on(‘connection’, function(socket){
            socket.on(‘sent’, function(data){
                        io.sockets.emit(‘receive’, data);
            });
});

Here, the Express server is initialised into the application and Socket.IO is initialised with the same server so that it is embedded into the app for further usage. The server is then started on Port 3000 on your local machine and can be accessed by using the URL localhost:3000.
When someone tries to access the URL while the server is active, a get request is passed on to the server; the request is then processed under the label ‘req’ and the response to this is labelled ‘res’ in terms of variables. The application then executes the function, which asks it to deploy the Web page named ‘welcome.html’ which resides in the same directory as test.js. Let’s now create a file named welcome.html and put the following code in it:

<!DOCTYPE html>
<html>
  <head>
    <meta charset=”utf-8”>
    <title>Hurray!</title>
  </head>
  <body>
    <div id=”content”>
            <form id=”name_form”>
               Your name:
<input size=”40” type=”text” id=”name” />
            <input type=”submit” />
            </form>
    </div>
<script src=”https://code.jquery.com/jquery-3.1.0.min.js”>
</script>
<script type=”text/javascript” src=”/socket.io/socket.io.js”></script>
<script>
jQuery(function($){
var socket = io.connect();
           var $nameForm = $(‘#name_form’);
           var $name = $(‘#name’);
 
           $nameForm.submit(function(e){
                                             e.preventDefault();
              socket.emit(‘sent’, $name.val());
                                $name.val(‘’);
                                    });
 
                  socket.on(‘receive’, function(data){
var html = ‘<h1>Welcome ‘ + data + ‘</h1><br /><i>This message was generated using socket.io</i>’;
$(‘#content’).html(html);
                                    });
                        });
            </script>
  </body>
</html> 

When done, go to the terminal and at the command prompt, type the following command:

$ node test

Open your browser and type localhost:3000.
If you see the result shown in Figure 2, congrats! You did everything exactly right. Here, we linked a socket.io file in the script section or mark up, which provided us the client-side functionalities of socket.io. Later, using our form, we ask for an input from our user and when he submits the form, we trigger the emit function of the socket, which sends the filled-out data to our Express server, which then processes our data and sends it back to the client using another emit function. Each emit function is uniquely named, like ‘send’ and ‘receive’.

Note: All this should be done without refreshing the page! To ensure that, we use jQuery’s preventDefault function when the form is submitted. 

Now, you are ready to move to the most important part of this article.

figure-2-the-result-of-the-test-application

Figure 2: The result of the test application

Building a real-time application
We will now implement a LAN based chat engine, which you can use to communicate with all the people connected on the same network as you. But first, it’s important to know how to access your apps on the local machine and access all the machines connected on the same network as your machine (your LAN).
Now, you can access your test app from any PC connected to your local network by just typing the IP address like this: “192.168.1.205:3000”.
Just as in our previous test application, we need to create a package.json file and put the following code in it:

 {
          “name”:”test_chat_application”,
          “version”:”0.0.1”,
          “private”:”true”,
          “dependencies”:{
                    “socket.io”:”1.4.8”,
                    “express”:”4.14.0”
          } }

Let’s run the script now by executing the following statement:

$ npm install

Next, let’s create a file named server.js, which will work like test.js and use this code for your server.js file:

var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server),
nicknames = [];

server.listen(3000);

app.get('/', function(req, res){
res.sendFile(__dirname + '/chat.html');
});

io.sockets.on('connection', function(socket){
socket.on('new user', function(data, callback){
if(nicknames.indexOf(data) != -1){
callback(false);
} else{
socket.nickname = data;
nicknames.push(socket.nickname);
io.sockets.emit('usernames', nicknames);
callback(true);
updateNicknames();
}
});

function updateNicknames(){
io.sockets.emit('usernames', nicknames);
}

socket.on('send message', function(data){
io.sockets.emit('new message', {msg: data, nick: socket.nickname});
});

socket.on('disconnect', function(data){
if(!socket.nickname) return;
nicknames.splice(nicknames.indexOf(socket.nickname), 1);
updateNicknames();
});
});
figure-3-fetching-the-local-ip-address

Figure 3: Fetching the local IP address

figure-4-local-chat

Figure 4: Local chat

The code is divided into three sections:
1. To start up the server
2. For user management
3. For sending and receiving messages
We should now discuss our client-side HTML file named chat.html:

<!DOCTYPE html>
<html>
<head>
<title>local chat</title>
<style type="text/css">
body{
font-weight: 400;
font-family: sans-serif;
}
h1{
font-weight: 300;
color: green;
text-align: center;
font-size: 24px;
}
#contentWrap{
display: none;
}
#chatWrap{
padding: 10px;
border: 2px solid black;
width: 300px;
box-sizing: border-box;
background: lightyellow;
float: left
}
#chat{
overflow-y: scroll;
height: 500px;
border: 1px solid green;
width: 275px;
background: white;
padding: 0 10px;
box-sizing: border-box;
margin-bottom: 30px;
}
#chat ul{
list-style-type: none;
padding: 0;
display: inline-block;

}
#chat ul li{
padding: 4px;
box-sizing: border-box;
border: 1px solid blue;
background: lightblue;
margin: 1px 0;
font-size: 14px;
width: 250px;
}
#chat ul li b{
border-right: 2px solid #000;
margin: 0 5px 0 0; 
}
#chatWrap form input{
height: 15px;
margin: 5px;
padding: 5px 5px;
width: 250px;
padding: 10px;
box-sizing: border-box;
}
#contentWrap #users{
margin-left: 320px;
width: 200px;
border: 1px solid black;
background: linear-gradient(120deg, #eee, #fff);

}

</style>
</head>
<body>
<h1>local chat</h1>

<div id="nickWrap">
<p>Enter a username:</p>
<form id="setNick">
<input size="35" type="text" id="nickname" />
<p id="error"></p>
<input type="submit" value="Enter chatroom" />
</form>
</div>
<div id="contentWrap">
<div id="chatWrap">
<div id="chat"><ul id="cht"></ul></div>
<form id="send-message">
<input type="text" id="message" placeholder="your message" />
</form> 
</div>
<div id="users">

</div>
</div>

<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script>
jQuery(function($){
var socket = io.connect();
var $nickForm = $('#setNick');
var $nickError = $('#error');
var $nickBox = $('#nickname');
var $users = $('#users');
var $messageForm = $('#send-message');
var $messageBox = $('#message');
var $chat = $('#cht');

$nickForm.submit(function(e){
e.preventDefault();
socket.emit('new user', $nickBox.val(), function(data){
if(data){
$('#nickWrap').hide();
$('#contentWrap').show();
} else{
$nickError.html('sorry, that username has been taken, try another one!');
}
});
$nickBox.val('');
});

$messageForm.submit(function(e){
e.preventDefault();
socket.emit('send message', $messageBox.val());
$messageBox.val('');
});

socket.on('usernames', function(data){
var html = '<h2>online users:</h2><hr />';
for(i=0; i < data.length; i++){
html += data[i] + '<br />';
}
$users.html(html);
});

socket.on('new message', function(data){
$chat.append("<li><b>" + data.nick + " </b>" + data.msg + "</li><br />");
});
})
</script>
</body>
</html>

Now, test this on other computers by accessing this application on using your IP.