Part 1: Real-Time Browser to Browser Communication Using Node.Js and Socket.Io
Introduction
Usually browsers communicate with the server, sending a request and getting a response. But what if it would be possible to link two or more browsers, while using the server to route requests between them? With the advance of server-side JavaScript, using Node.js, and socket connections supported by HTML5-capable browsers (or frameworks to emulate the functionality in older versions, i.e. Socket.IO) this task has become trivial.
Node.js
Node.js provides a server-side JavaScript implementation, allowing for event-driven, non-blocking I/O programming, enabling real-time application development. It relies on Google Chrome's JavaScript runtime, currently (Node.js version 0.11.1) implementing the ECMA-262 ECMAScript Language Specification.
Socket.IO
Socket.IO is a JavaScript framework that enables real-time browser-to-server communication, providing an API that encapsulates different transport mechanisms. Its browser compatibility starts with versions of IE 5.5, Safari 3, Firefox 3, Opera 10.61, Google Chrome 4, as well as mobile browsers such as iPhone/iPad Safari and Android/WebOS Webkit.
The underlying transport mechanisms are based on WebSocket, Adobe Flash Socket, AJAX long polling, AJAX multipart streaming, Forever Iframe, and JSONP Polling. The transport mechanism is automatically selected without the developer having to specify it.
Prerequisites
This article assumes both tools are available on your server. Node.js is available as a port in FreeBSD, named node, and as a package in Debian, named nodejs. Socket.IO can be installed using Node.js's NPM package manager (npm port/package in FreeBSD and Debian), as described here.
Server Side: Accepting New Connections
Below I am presenting the source code of a basic connection application that adds a console message when the client connects or disconnects.
Let's begin writing an object that handles the socket's connect and disconnect events. For good design, this object follows the JavaScript Revealing Prototype Pattern.
Step 1: Prepare the Server Class
Prepare a Server class that takes in a configuration object through its constructor.
/**
* Messaging server.
* @class Provides server functionality.
* @constructor
* @param {Object} config Server configuration object.
* Supported keys are: port (listening port number),
* and socket (socket listener configuration object).
*/
var Server = function( config ) {
// Store configuration, in a 'private' property
this._config = config;
}
Step 2: Load Libraries and Prepare Listeners
/**
* Method used for loading the 'http' and 'socket.io' classes,
* and creating the listeners.
* @function
*/
Server.prototype.loadLibraries = function() {
// HTTP Server, required for serving Socket.IO JS file
// NOTE: The HTML file that makes use of it,
// is served by a standard HTTP server.
this._httpServer = require('http').createServer();
// Socket.IO
this._socketIo = require('socket.io').listen(
this._httpServer,this._config.socket
);
}
Step 3: Open the Listening Port and Attach Event Handlers
/**
* Method used for preparing the server listeners, and attaching event handlers.
* @function
*/
Server.prototype.init = function() {
// Load required libraries.
this.loadLibraries();
// Open port for incoming connections
this._httpServer.listen( this._config.port );
// Attach a Socket.IO connection handler
// This handler in turn will attach application specific event handlers.
this._socketIo.sockets.on( 'connection', function ( socket ) {
// Attach the socket disconnect handler
// This handler in turn will attach application specific event handlers.
socket.on( 'disconnect', function () {
// TODO: Add disconnect event handlers here
console.log( 'Client disconnected: ' + socket.handshake.address.address );
}.bind( this ) );
// TODO: Add connection event handlers here
console.log( 'Connection from: ' + socket.handshake.address.address );
}.bind( this ) );
}
Step 4: Create a New Server Instance
// Create server
new Server( {
port: 10000 // Listening port,socket: { // Socket configuration
log: false // Disable logging
}
} ).init(); // Call the init function
Start the Server
Once the code is ready, start the Node.js server:
nodejs server.js
Client Side: Initiate a Connection
Node.js can itself be used to serve the HTML/JS content. In this example, the Node.js server provides the Socket.IO JavaScript code, while the client JavaScript and HTML code is served by any server. Similar to the server code, this object makes use of the Revealing Prototype Pattern.
Step 1: Prepare the Client Class
Prepare a Client class that takes in a configuration object through its constructor.
/**
* Messaging client.
* @class Provides client functionality.
* @constructor
* @param {Object} config Client configuration object.
* Supported keys are: port (listening port number), host (URL)
*/
var Client = function( config ) {
// Store configuration, in a 'private' property
this._config = config;
}
Step 2: Open a Connection and Attach Event Handlers
/**
* Method used for initiating a connection, and attaching event listeners.
* @function
*/
Client.prototype.init = function() {
// Create connection
this._socket = io.connect( this._config.host + ':' + this._config.port );
// Attach a 'connect' event handler.
this._socket.on( 'connect', function() {
// TODO: Add 'connection' event handler.
console.log( "Connected." );
}.bind( this ) );
// TODO: Add other events here.
}
Step 3: Create a Client Instance
new Client( {
port: 10000,host: 'http://localhost'
} ).init();
Step 4: Load the Required Files in HTML
The socket.io.js file is served by the Node.js server, while the client.js file is served by another HTTP server.
What's Next?
In a next article, I will present how to extend this object and add application-specific events and handlers to allow message routing between multiple clients.