WEBSOCKET COMMUNICATIONS - A SIMPLE START TO JQUERY, JAVASCRIPT, AND HTML5 FOR BEGINNERS (2014

A SIMPLE START TO JQUERY, JAVASCRIPT, AND HTML5 FOR BEGINNERS (2014)

CHAPTER 9: WEBSOCKET COMMUNICATIONS

There are scenarios that may require the establishment of two-way communication between the client and the server. A sample application that requires this form of communication is a chat application. This chapter gives an elaborative study of how web socket communication can be established and used.

Communicating by using WebSocket

Websocket communications are established using the WebSocket protocol, which uses the TCP connection for establishing a full-duplex communication pathway. The protocol has been standardized by the IETF (RFC 6455) and the working draft of the WebSocket API is in W3C.

This technology has replaced the concept of long polling. In this case, the client sends a request and keeps waiting for a response until a response is received. The benefit of this approach is that the connection remains open and as and when the data is available, it is immediately sent. However, the connection may be timed out and a re-establishment may be required.

Understanding WebSocket Protocol

The WebSocket protocol allows bi-directional connection establishment and is designed for implementation for web servers and clients. This technology only interacts with the handshake and is interpreted as a transition from the http to WebSocket. The frame of this protocol has no headers and an overhead of 2 bytes. It is a lightweight technology and its high performance allows communication of live content and games.

Defining WebSocket API

The heart of the WebSocket technology is WebSocket object. This object is defined on the window object and contains the following members:

● close

● WebSocket constructor

● binaryType

● send

● extensions

● bufferedAmount

● onerror

● url

● onclose

● onopen

● onmessage

● readyState

● protocol

How to Implement WebSocket Object

The WebSocket communication is based on TCP and thus, it operates on port number 80. You can use any HTML form for demonstration. The WebSocket url is of the ws:// and wss:// form. In order to implement this form, you need to create an object of the WebSocket API, which can then be configured using onopen, onclose, onerror and onmessage events. The default.js file must be modified in the following manner:

/// <reference path="_references.js" />

var wsUri = 'ws://echo.websocket.org/';

var webSocket;

$(document).ready(function () {

if (checkSupported()) {

connect();

$('#btnSend').click(doSend);

}

});

function writeOutput(message) {

var output = $("#divOutput");

output.html(output.html() + '<br />' + message);

}

function checkSupported() {

if (window.WebSocket) {

writeOutput('WebSocket is supported!');

return true;

}

else {

writeOutput('WebSockets is not supported');

$('#btnSend').attr('disabled', 'disabled');

return false;

}

}

function connect() {

webSocket = new WebSocket(wsUri);

webSocket.onopen = function (evt) { onOpen(evt) };

webSocket.onclose = function (evt) { onClose(evt) };

webSocket.onmessage = function (evt) { onMessage(evt) };

webSocket.onerror = function (evt) { onError(evt) };

}

function doSend() {

if (webSocket.readyState != webSocket.OPEN)

{

writeOutput("NOT OPEN: " + $('#txtMessage').val());

return;

}

writeOutput("SENT: " + $('#txtMessage').val());

webSocket.send($('#txtMessage').val());

}

function onOpen(evt) {

writeOutput("CONNECTED");

}

function onClose(evt) {

writeOutput("DISCONNECTED");

}

function onMessage(evt) {

writeOutput('RESPONSE: ' + evt.data);

}

function onError(evt) {

writeOutput('ERROR: ' + evt.data);

}

When you create a WebSocket object, a connection to URI is automatically initiated. The function, connect, subscribes the object the events mentioned above. The message is sent using the doSend function. However, the readyState property of the object is checked before sending any message. The values of the property can be as follows:

● Closed = 3

● Closing = 2

● Open = 1

● Connecting = 0

Upon reception of message from the server, the client calls the onMessage function, which passes the event object. The property, data, of this object, contains the message sent from the server. On the contrary, if an error has occurred, then the onError function is called and the data property contains the reason for error generation. In some cases, the data property may be ‘undefined’. This is particularly the case in scenarios where the connection has timed-out.

How to Deal with Timeouts

A timeout is identified when no activity is triggered for as long as 20 minutes. One of the most effective ways to deal with timeouts is sending an empty message to the server on a periodic basis. This can be done in the following manner.

/// <reference path="_references.js" />

var wsUri = 'ws://echo.websocket.org/';

var webSocket;

var timerId = 0;

$(document).ready(function () {

if (checkSupported()) {

connect();

$('#btnSend').click(doSend);

}

});

function writeOutput(message) {

var output = $("#divOutput");

output.html(output.html() + '<br />' + message);

}

function checkSupported() {

if (window.WebSocket) {

writeOutput('WebSockets supported!');

return true;

}

else {

writeOutput('WebSockets NOT supported');

$('#btnSend').attr('disabled', 'disabled');

return false;

}

}

function connect() {

webSocket = new WebSocket(wsUri);

webSocket.onopen = function (evt) { onOpen(evt) };

webSocket.onclose = function (evt) { onClose(evt) };

webSocket.onmessage = function (evt) { onMessage(evt) };

webSocket.onerror = function (evt) { onError(evt) };

}

function keepAlive() {

var timeout = 15000;

if (webSocket.readyState == webSocket.OPEN) {

webSocket.send(‘’);

}

timerId = setTimeout(keepAlive, timeout);

}

function cancelKeepAlive() {

if (timerId) {

cancelTimeout(timerId);

}

}

function doSend() {

if (webSocket.readyState != webSocket.OPEN)

{

writeOutput("NOT OPEN: " + $('#txtMessage').val());

return;

}

writeOutput("SENT: " + $('#txtMessage').val());

webSocket.send($('#txtMessage').val());

}

function onOpen(evt) {

writeOutput("CONNECTED");

keepAlive();

}

function onClose(evt) {

cancelKeepAlive();

writeOutput("DISCONNECTED");

}

function onMessage(evt) {

writeOutput('RESPONSE: ' + evt.data);

}

function onError(evt) {

writeOutput('ERROR: ' + evt.data);

}

How to Handle Disconnects

Connections may sometime close errors concerning the network. Therefore, you may be required to call the connect function while you are inside the construct of the onClose function. This may lead to issues. A common problem faced in this regard is that the server is unable to identify that this new connection request belongs to a client that already exists. You can handle this issue by sending an identification message to the server.

How to Deal with Web Farms

You may need to run your application in web farm, in which case the incoming requests may be handled by many servers. Multiple server are used to perform load balancing and performance optimization. In this case, you can implement sticky servers, which ensures that a client is served by only one server. In other words, all the requests by one client are processed by the same server. This helps you to address issues that may arise due to open connections. These problems can also be handled using products like Microsoft App Fabric Caching Service and Redis.

How to Use WebSocket Libraries

Dealing with all the issues mentioned above can be challenging. Therefore, the best way to deal with the situation is to use server and client libraries. There are several libraries like SignalR and Socket.IO are available for you to explore.