Creating an HTML Web Socket Client With JQuery.WebSocket

1 Comment

In my previous post Setting Up A Web Socket Service With Node.js on Windows I showed how a web socket server can quickly and easily be created using node.js. In the post was included a sample node.js javascript driver file which created an echo server, simply returning any received messages back to the client.

My aim in this post is to show how you can connect to the web socket server from HTML to create a basic echo application. This will prove that we can fully implement two-way communication between server and client using node.js and web sockets in the Google Chrome browser. Client side web sockets interfacing with a web socket server enable true duplex communication over the web, facilitating the creation of complex and responsive LOB applications.

This post will show just how easy it is to create a simple web socket client in HTML and how to send and receive messages.

Pre-requisites

In order to get started with the information in this post you will need the following:

  1. A running node.js instance, with the WebSocket-Node plugin, using the echo driver file from my previous post – Setting Up A Web Socket Service With Node.js on Windows
  2. JQuery, JQuery.WebSocket and JQuery.JSON javascript files
  3. A web socket compatible browser (i.e. Google Chrome 16)
Issues With JQuery.WebSocket

JQuery.WebSocket is a JQuery based helper file that simplifies the creation of WebSockets in Javascript. The code is elegant and very useful but unfortunately the latest published version has some bugs for which I could not find fixes on the official website.

As a result I fixed the bugs during my investigations and also added a web socket protocol parameter to the constructor (more on this later). Below is the fixed code – simply  copy and paste over the code in the jquery.websocket-0.0.1.js file.

/*
* jQuery Web Sockets Plugin v0.0.1
* http://code.google.com/p/jquery-websocket/
*
* This document is licensed as free software under the terms of the
* MIT License: http://www.opensource.org/licenses/mit-license.php
*
* Copyright (c) 2010 by shootaroo (Shotaro Tsubouchi).
*/
(function ($) {
    $.extend({
        websocketSettings: {
            open: function () { },
            close: function () { },
            message: function () { },
            options: {},
            events: {}
        },
        websocket: function (url, protocol, s) {
            var ws = WebSocket ? new WebSocket(url, protocol) : {
                send: function (m) { return false },
                close: function () { }
            };
            ws._settings = $.extend($.websocketSettings, s);
            $(ws)
			.bind('open', $.websocketSettings.open)
			.bind('close', $.websocketSettings.close)
			.bind('message', $.websocketSettings.message)
			.bind('message', function (e) {
			    var m = $.evalJSON(e.originalEvent.data);
			    var h = $.websocketSettings.events[m.command];
			    if (h) h.call(this, m);
			});
            ws._send = ws.send;
            ws.send = function (type, data) {
                var m = { command: type };
                m = $.extend(true, m, $.extend(true, {}, $.websocketSettings.options, m));
                if (data) m['data'] = data;
                try {
                    this._send($.toJSON(m));
                }
                catch (ex) {
                    alert(ex);
                    return false;
                }
                return true;
            }
            $(window).unload(function () { ws.close(); ws = null });
            return ws;
        }
    });
})(jQuery);
Web Socket HTML Client Code
The HTML for the web socket client is straightforward.
I have pasted my example HTML file below. You will need to ensure that you change any Javascript references at the top of the page (the script tags) to match the locations of your script files.
<html lang="en">
<head>
    <title>Node Based Echo</title>
    <script src="/Scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
    <script src="/Scripts/jquery.websocket-0.0.1.js" type="text/javascript"></script>
    <script src="/Scripts/jquery.json-2.3.js" type="text/javascript"></script>
</head>
<body>
    <script type="text/javascript">

        // sends a message to the websocket server
        function sendToServer() {

            ws.send('krakenmsgA', '{ messageTextA: ' + $('#echoText').val() + ' }');
            ws.send('krakenmsgB', '{ messageTextB: ' + $('#echoText').val() + ' }');
        }

        // set-up web socket
        var ws = $.websocket("ws://localhost:8080/", "kraken-protocol", {
            open: function () { },
            close: function () { alert('websocket has been closed'); },
            events: {
                krakenmsgA: function (e) { $('#returnText').append(e.data + "<br/>"); },
                krakenmsgB: function (e) { $('#returnText').append(e.data + "<br/>"); }
            }
        });

    </script>
    <div>
        <div style="float: left; clear: left; padding-top: 2px;">
            Your text:
        </div>
        <div style="float: left; padding-left: 20px;">
            <input type="text" id="echoText" style="width: 150px;" required />
        </div>
        <div style="clear: left;">
            <input type="button" onclick="javascript:sendToServer();" value="Send" />
        </div>
        <div id="returnText" style="clear: left; height: 200px; padding-top: 30px;">
        </div>
    </div>
</body>
</html>

As you can see the code is very straightforward. The HTML renders a very simple form with a text box and button. When the button is clicked a Javascript call is made to send a message to the web socket server.

Opening a web socket connection is remarkably easy – this simple line of code manages the process:

var ws = $.websocket("ws://localhost:8080/", "kraken-protocol", { ... });

One important thing to note is the second parameter passed to the constructor which is one of the extensions I made to the JQuery.WebSocket script. The WebSocket-Node node.js plugin used to host the web socket server requires a protocol contract to exist between the server and client. If you view my previous post Setting Up A Web Socket Service With Node.js on Windows, the node.js script file creates a server web socket with the protocol as ‘kraken-protocol’. The client must also specify the same protocol otherwise the server will not allow the client to connect. It is unimportant what the actual protocol is – the important thing is that the server and client match. Obviously the port on which the server is running must be specified in the first parameter to the constructor as part of the URL of the web socket server.

Sending a message to the web socket server is also very straightforward in our example:

ws.send('krakenmsgA', '{ messageTextA: ' + $('#echoText').val() + ' }');

We are using JQuery in this example to retrieve the value specified by the user in the text box, which has the id echoText.

Behind the scenes the JQuery.WebSocket script sends a message to the web socket server in a JSON wrapper, with a command property set to the value of the first parameter of the send method. In this case the command value would be set to ‘krakenmsgA’.

The nice thing about JQuery.WebSocket is that it binds events that correspond to the type of message that is sent, simplifying the message handling process. For example, the line

ws.send('krakenmsgA', '{ messageTextA: ' + $('#echoText').val() + ' }');

sends a message to the web socket server of type ‘messageTextA’. The return message event corresponding to this type can then be handled by simply creating an event handler, as shown in the following code.

var ws = $.websocket("ws://localhost:8080/", "kraken-protocol", {
            open: function () { },
            close: function () { alert('websocket has been closed'); },
            events: {
                krakenmsgA: function (e) { $('#returnText').append(e.data + "&lt;br/&gt;"); },
                krakenmsgB: function (e) { $('#returnText').append(e.data + "&lt;br/&gt;"); }
            }
        });

This code both opens the connection and handles the required events. To handle a new message type, simply add a new handler to the websocket declaration.

Conclusions

Connecting to a web service from HTML and creating a simple echo application is remarkably trivial. My experiences of network programming with raw sockets in the .NET world led me expect that the process would prove problematic but this appears not to be the case. The web socket implementation in Google Chrome nicely handles the opening and closing of web sockets, including when communication with the server is lost, and looks resilient during testing. Open and close events are raised by the web socket, enabling clean handling of connection issues.

The use of JQuery.WebSocket makes life easier and provides a well structured event interface implementation, although you will need to use the amended script from this post if you wish to use these examples.

I can see many potential pitfalls, however, that will lead to such an implementation being problematic in a large LOB application. Code structure and abstraction are the obvious issues and I’m not yet sure of the best way to structure a large application based on HTML 5 and Javascript. This will definitely be a major consideration as I move further into the development of Kraken Office and I’m sure will be dealt with in future posts.

I am expecting Javascript structuring and code management to be one of the trickiest elements of the project, with Javascript acting as our controller between the UI elements and middleware. Without careful planning and code organisation the client side of the project will quickly become unmaintainable.

These are issues for another day, however.

For my next challenge I will be looking into the Redis implementation and how I can use the message broker functionality to loosely couple communication between system components.

Till next time – happy coding!

Advertisements

Setting Up A Web Socket Service With Node.js on Windows

2 Comments

In my previous post on selecting techologies for the Kraken Office project I explained that I have decided to use the node.js framework to create the required web socket server infrastructure.

There are a couple of existing web tutorials aimed at setting up web sockets with node.js but I could find none that took you through the process from the standpoint of no existing experience with the node.js framework.

Node.js is a lightweight framework used to create services. It is single threaded and can be easily scaled. Node.js scripts are written in Javascript and there are a number of plug-ins available.

Installing Node.js

To run node.js on Windows you should get the installer from here – node.js Windows installer. I am working with version 0.6.9 – installation of node.js is a simple one click process. Once node.js is installed you will need to get the WebSocket-Nodeplug-in to enable support for web sockets. There are other plug-ins available to enable the creation of web sockets but I have found WebSocket-Node stable and easy to use.

Using NPM to install WebSocket-Node

NPM is a package manager for node.js. It enables you to publish and manage node.js installations and plug-ins. You do not need to separately download NPM code as it is already included in the node.js installation.

Using NPM you can download WebSocket-Node and install it in one easy action. There is currently an issue (at the time of writing) with the latest version of WebSocket-Node on Windows – see this issue for further details. A previous version (v1.0.3) installs and works with no problems so I have used this to set-up node.js and WebSocket-Node on my local server.

In order to use NPM to install WebSocket-Node simply follow these steps:

  1. Open a command prompt window
  2. Navigate to the root of your node.js installation folder using the CD command – this will probably be in your Program Files directory
  3. Execute npm install websocket@1.0.3 in the command prompt window
  4. WebSocket-Node will be download from the npm repository and integrated into your existing node.js installation
Getting Started With Node.js and WebSocket-Node
Once you have successfully installed node.js and the WebSocket-Node extension you can now very easily create a web socket server.
The following is an example of how to create a simple echo web socket server taken directly from the WebSocket-Node website:
var WebSocketServer = require('websocket').server;
var http = require('http');

var server = http.createServer(function(request, response) {
    console.log((new Date()) + ' Received request for ' + request.url);
    response.writeHead(404);
    response.end();
});
server.listen(8080, function() {
    console.log((new Date()) + ' Server is listening on port 8080');
});

wsServer = new WebSocketServer({
    httpServer: server,
    // You should not use autoAcceptConnections for production
    // applications, as it defeats all standard cross-origin protection
    // facilities built into the protocol and the browser.  You should
    // *always* verify the connection's origin and decide whether or not
    // to accept it.
    autoAcceptConnections: false
});

function originIsAllowed(origin) {
  // put logic here to detect whether the specified origin is allowed.
  return true;
}

wsServer.on('request', function(request) {
    if (!originIsAllowed(request.origin)) {
      // Make sure we only accept requests from an allowed origin
      request.reject();
      console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
      return;
    }

    var connection = request.accept('kraken-protocol', request.origin);
    console.log((new Date()) + ' Connection accepted.');
    connection.on('message', function(message) {
        if (message.type === 'utf8') {
            console.log('Received Message: ' + message.utf8Data);
            connection.sendUTF(message.utf8Data);
        }
        else if (message.type === 'binary') {
            console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
            connection.sendBytes(message.binaryData);
        }
    });
    connection.on('close', function(reasonCode, description) {
        console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
    });
});

To start / stop the web socket server simply follow these steps:

  1. Paste the above example into a file called WebSocketV1.js
  2. Save the file into the root of your node.js installation (the simplest way to get started)
  3. Open a command window and navigate to your node.js installation direction using the CD command
  4. Execute node WebSocketV1 in the command prompt window
  5. The web socket server will be started on the specified port
  6. To stop the server simply close the command window

I hope this example shows just how easy it is to get a web socket server up and running using node.js and the WebSocket-Node extension.

Obviously this post only scratches the surface of node.js but hopefully gives you an overview of how to get your first node.js server up and running.There are a multitude of other resources available on the web, not least the node.js documentation, to help you move forward.

Next Steps

In the context of the Kraken Office project I am presently getting all of the components outlined in my previous architecture post up and running so that I can prove the architecture design is feasible and the necessary components are fit for purpose. Node.js appears to be easy to configure and set-up and I am happy to continue to use it for my web socket server requirements.

Further posts will deal with using node.js to create the web socket server to be used in the Kraken Office project and will cover integration with the Redis server’s message broker, which is the link between the front end web socket server and the middleware components. See the architecture diagram in the architecture post for full details.

The next step is to create a simple HTML 5 application in ASP.NET MVC 3 to get JQuery and the associated web socket libraries configured, set-up and interacting with the node.js web socket server. Once this is done I will have completed the initial proof of concept for the technologies selected for the front end of the system and can move on to the messaging architecture.