Programming in HTML5 with JavaScript & CSS3 Training Guide
Notes from Programming in HTML5 with JavaScript & CSS3 Training Guide by Glenn Johnson.
This is part of my study material for passing Microsoft’s Exam 70-480: Programming in HTML5 with JavaScript & CSS3 certification exam.
WebSockets allows initiating communication from the browser to the server or from the server to the browser. If the server can send messages to the browser, the browser doesn’t need to poll the server for status info.
An example of two-way communication is a chat room app by which the server can notify many browsers that a message was received from a browser.
The WebSocket protocol is a web technology that provides full-duplex communications over a single TCP connection.
WebSocket replaces the long polling concept.
The WebSocket protocol provides a standardized way for the server to send content to the browser without being solicited by the client and to allow messages to be passed back and forth while keeping the connection open. A two-way (bidirectional), ongoing conversation can take place between a browser and the server.
The WebSocket protocol is designed to be implemented in web browsers and web servers, but any client or server application can use it. The protocol is an independent, TCP-based protocol. Its only relationship to HTTP is that its handshake is interpreted by HTTP servers as a request to switch to WebSocket protocol.
Each frame of WebSocket protocol has only 2 bytes of overhead, and there are no headers. The light weight nature of the WebSocket protocol enables more interaction between a browser and website. This performance increase makes the WebSocket protocol an easy choice for communicating when it’s necessary to deliver live content and real-time gaming.
At the heart of the WebSocket API is the WebSocket
object, which is defined on the window object. You can easily test if this object exists to determine whether the browser supports WebSocket. The WebSocket object contains the following members:
onmessage
event receives.WebWSocket protocol communications typically use TCP port number 80, so environments that block non-standard Internet connections by using a firewall will still pass WebSocket packets.
In the following example, a webpage is created that calls the WebSocket.org echo server, which will return the message passed to it. Consider the following webpage that contains a text box for entering a message and a button to send the message to a server; all output is appended to the <div id="divOutput">
element.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>WebSocket</title>
</head>
<body>
<h1>WebSocket Test</h1>
Enter message: <input type="text" name="txtMessage" id="txtMessage"><br>
<button id="btnSend" type="button">Send Message</button>
<div id="divOutput"></div>
<script src="scripts/jquery.js"></script>
<script src="scripts/index.js"></script>
</body>
</html>
Whereas an HTTP URL begins with http://
or https://
for secure HTTP, the WebSocket URL begins with ws://
or wss://
for secure WebSocket protocol.
In the JavaScript code, you create a WebSocket
object and configure the onopen
, onmessage
, and onclose
events. Call the send
method to send a message, and the onmessage
event triggers if there is a response.
// ES5
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('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 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); }
In this example, wsUri
is set to the WebSocket.org server, which echoes messages sent to it. The ready
function calls the checkSupported
function to see whether WebSocket is supported. This is accomplished by checking whether the window object has a WebSocket object. If so, the connect
function is called.
The connect
function instantiates WebSocket. The constructor accepts a URI argument. Creating the WebSocket object automatically initiates communications to the URI to attempt to open the connection asynchronously. The connect
function also subscribes to the onopen
, onclose
, onmessage
, and onerror
events.
It’s important to subscribe to these events immediately because the connection might open quickly, and you want to ensure that you are subscribed to the onopen
event as soon as possible so you don’t miss the event.
Quick check
- Can you create a WebSocket object and call the open method when you want to open a WebSocket connection?
Answer
- No, there is no open method on the WebSocket object. When you instantiate the WebSocket object, it automatically attempts to open asynchronously.
The doSend
function sends a message to the server. Before sending the message, this function checks the readyState
property of the WebSocket object. The readyState property contains one of the following values.
The readyState
property will be set to one of the numeric values, but you can use the constants as shown in the doSend
function that tests for webSocket.OPEN
. If the WebSocket is not open, a message is displayed, and the function returns without sending. If WebSocket is open, a message is displayed, and the message is sent using the send
method.
When a message is received from the server, the onMessage
function is called, and the event
object is passed. The data
property of the event
object contains the message.
When an error is received, the onError
function is called, and the event
object is passed. An error can come from the server or be generated when either the client cannot connect to server or the connection is timed out. Depending on the error, the event
object might pass the cause on the data
property. You might also find that the data
property is undefined
, especially is a timeout scenario.
When the page is displayed a message shows ‘WebSocket Supported!’. The CONNECTED message is displayed when the connection is open, and a response is displayed if a message is entered and the ‘Send Message’ button is clicked to send the message to the server.
One way of dealing with timeouts is to send an empty message to the server periodically.
// ES5
var timerId = 0;
function keepAlive() {
var timeout = 15000;
if (webSocket.readyState === webSocket.OPEN) {
webSocket.send('');
}
timerId = setTimeout(keepAlive, timeout);
}
function cancelKeepAlive() {
if (timerId) {
clearTimeout(timerId);
}
}
function onOpen(evt) { writeOutput('CONNECTED'); keepAlive(); }
function onClose(evt) { writeOutput('DISCONNECTED'); cancelKeepAlive();}
At the top is the declaration of the timerId
. A keepAlive
function has been added that sends an empty message every 15 seconds. The keepAlive
function is called when the onOpen
function is executed and is recursive; it doesn’t stop until the timer is cancelled by using the timerId
.
A cancelKeepAlive
function has been added to cancel the looping of the keepAlive
function, and it’s called when the onClose
function is called.
In addition to providing the keepAlive capability, you might also need to deal with connections that close due to network errors. This can require you to call the connect
function from within the onClose
function. Your application may need to handle this by forcing the client to send an identification message.
Sometimes, when pushing your WebSocket application to production, you need your application to run in a web farm, where multiple servers handle incoming requests. These requests are load balanced to provide the best performance.
You can share state across multiple web servers by using one of the many products that handle this problem such as Redis & MS App Fabric Caching Service.
Quick check
- Do the WebSocket protocol and WebSocket API provide native support for load balancing in a web farm?
Answer
- No, there is no native support for web farm load balancing with WebSocket protocol and the WebSocket object.
Dealing with timeouts, dropped connections, incompatible browsers, and web farms can be a daunting task. For this reason it’s usually a better practice to use a library that can handle this task for you in a consistent manner. The thing to understand though is that these libraries run at both the client and the server. Here’s a short list.
SignalR is a Microsoft library for ASP.NET developers. It is meant to be implemented on an ASP.NET website, using a .NET language such as C# on the server and JavaScript on the client.
SignalR simplifies the addition of real-time web functionality to your applications. It uses WebSocket when it’s available but gracefully falls back to techniques such as long polling when WebSockets is not available.
Socket.IO is a WebSocket library created by Guillerma Rauch who also created Engine.IO and other open source libraries. Socket.IO has both a client-side and server-side library, each written in JavaScript. The server side is for use with Node.js; It uses feature detection to decide whether the connection will be established with WebSocket, Ajax long polling or Flash polling.
onclose
, onmessage
, onerror
, and onopen
.readyState
property on the WebSocket object to obtain the state of the connection.ws://
for WebSocket protocol or wss://
for secure WebSocket protocol.