How to Use WebSockets

Although they are not yet fully supported, WebSockets are one of the most promising technologies that HTML5 has to offer.  WebSockets give browsers the ability to communicate with a web server over a full-duplex communication channel.  This is a big deal because it has the potential to revolutionize dynamic web pages in a few big ways.

One benefit of WebSockets is improved performance.  The traditional HTTP request/response model incurs a lot of overhead due to the HTTP headers.  However, once connected, WebSockets allow the client and server to communicate directly, without headers.  This reduces the amount of data being transmitted, as well as decreasing the load on the network.  Browser based games and real time applications are likely the biggest beneficiaries of this speedup.

WebSockets also provide an elegant implementation of push technology.  Push technology refers to communication that is initiated by the server.  This contrasts the typical Web communication model of client initiated communication (also known as pull technology).  Prior to HTML5, push technology was implemented through a number of hacks such as long polling.  In long polling, the client makes an AJAX request to the server.  If the server doesn’t have any data to return, it simply leaves the connection open.  Once data becomes available, the server sends it back to the client.  The client then immediately makes another request, ensuring that an open connection is always available for push data.  WebSockets make these techniques obsolete by providing true push technology.  The additional overhead of repeatedly polling the server is also mitigated by using WebSockets.

Detecting WebSocket Support

Since WebSocket support is still hit or miss, it is necessary to detect them before trying to use them.  The following function can be used to detect WebSocket support.  The function returns true if WebSockets are supported, and false if they are not.

function webSocketSupported() {
  return "WebSocket" in window;
}

Opening a WebSocket

WebSockets are created via the WebSocket() constructor function shown below.

WebSocket( url[, protocols] )

The constructor’s first argument is the URL that the WebSocket will connect to.  When a WebSockets is constructed, it immediately attempts to connect to the given URL.  There is no way to prevent or postpone the connection attempt.  After construction, the WebSocket’s URL is accessible via its “url” property.  The URL specifies the following details about the connection.

  • Scheme ― The scheme must be “ws” or “wss”.  The “ws” scheme is insecure, while “wss” indicates a secure connection.  Pages that are served over HTTP should use “ws” WebSockets, while HTTPS pages should use “wss”.  Attempting to use a scheme other than “ws” or “wss” will cause an error.
  • Host ― The host is the name or IP address of the server.
  • Port ― This specifies the remote port to connect to.  If the port is not specified then a default is selected based on the scheme.  ”ws” connections default to port 80, while “wss” connections default to 443.
  • Resource Name ― The resource name is the path component of the URL which follows the host/port.  This includes the URL query component (the part following a question mark), if one is present.  The resource name can be omitted, in which case it defaults to a forward slash ‘/’.

The generic format of a WebSockets URL, as well as a few example URLS are shown below.

scheme://host:port/resource
ws://localhost:8080/echo
wss://cjihrig.com

The WebSocket constructor’s second argument, “protocols”, is optional.  If it is specified, it should either be a string or an array of strings.  The string(s) are subprotocol names.  In order for a connection to be established, the server must support at least one of the subprotocols.  After construction, the protocol argument is stored in the WebSocket’s “protocol” property.

Closing WebSockets

As a general programming rule, you should always close things that you open.  This rule also applies to WebSockets.  To close a WebSocket connection, use the close() method.  The syntax for close() is shown below.  close() takes two arguments, “code” and “reason”, which are both optional.  The “code” is a numeric status sent to the server.  A value of 1000 indicates that the connection was closed normally.  All of the possible “code” values are discussed here.  The “reason” field is a string describing the circumstances of the close event.  Typically, close() is called with no arguments.

close( [code[, reason]] )

Checking a Connection’s Status

A WebSocket’s state can be checked at any time via its “readyState” property.  During its lifetime, a WebSocket can be in four possible states.  The following list describes each of these four states.

  • Connecting ― When a WebSocket is constructed, it attempts to connect to its URL.  During this time it is considered to be in the connecting state.  A WebSocket in the connecting state has a “readyState” value of 0.
  • Open ― After a WebSocket successfully connects to its URL it enters the open state.  A WebSocket must be in the open state in order to send and receive data over the network.  A WebSocket in the open state has a “readyState” value of 1.
  • Closing ― When a WebSocket is closed, it must first communicate to the server that it is disconnecting.  During this period of communication, the WebSocket is considered to be in the closing state.  A WebSocket in the closing state has a “readyState” value of 2.
  • Closed ― A WebSocket enters the closed state once it successfully disconnects from the server.  A WebSocket in the closed state has a “readyState” value of 3.

It is not good programming practice to hard-code constant values.  To help avoid this situation, the WebSocket interface defines static constants representing the possible “readyState” values.  The following example shows how these constants can be used to evaluate the state of a connection.

switch (socket.readyState) {
  case WebSocket.CONNECTING:
    // do something
    break;
  case WebSocket.OPEN:
    // do something
    break;
  case WebSocket.CLOSING:
    // do something
    break;
  case WebSocket.CLOSED:
    // do something
    break;
  default:
    // this never happens
    break;
}

Handling Binary Data

JavaScript has traditionally used text formats like JSON and XML to transmit data as strings.  However, HTML5 allows applications to also work directly with binary data in order to increase performance.  WebSockets support two types of binary data ― binary large objects (blobs) and ArrayBuffers.  However, an individual WebSocket can only work with one of the two binary formats at a time.  When a WebSocket is created, it is initially set up to handle blob data.  The “binaryType” property is used to switch between blob and ArrayBuffer support.  The following example shows how to switch between the two binary formats.

socket.binaryType = "blob";
// receive some blob data

socket.binaryType = "arraybuffer";
// now receive ArrayBuffer data

WebSocket Event Handlers

Event handlers play an important role in WebSockets programming.  For example, all received data is processed by an event handler.  The remainder of this section describes each of the WebSockets event handlers in more detail.

onopen

When a WebSocket transitions into the open state, its “onopen” event handler is called.  An example “open” event handler is shown below.

socket.onopen = function(event) {
  // handle open event
};

Event handlers can also be created using the addEventListener() method.  The following example uses addEventListener() to attach an event handler to a WebSocket’s “open” event.  This alternative syntax is preferred to “onopen” because it allows multiple handlers to be attached to the same event.

socket.addEventListener("open", function(event) {
  // handle open event
});

onmessage

When a WebSocket receives new data from the server, its “onmessage” event handler is called.  The received data is stored in the “data” field of the “message” event.  An example “onmessage” event handler is shown below.  If binary data is being received, the  WebSocket’s “binaryType” property should be set accordingly before the event handler is called.

socket.onmessage = function(event) {
  var data = event.data;
  // process data as string, blob, or ArrayBuffer
};

The “onmessage” event handler can also be implemented using addEventListener().  An example of this is shown below.

socket.addEventListener("message", function(event) {
  var data = event.data;
  // process data as string, blob, or ArrayBuffer
});

onclose

When a WebSocket is closed, its “onclose” event handler is called.  The event object passed to “onclose” has three fields named “code”, “reason”, and “wasClean”.  The “code” is a numeric status provided by the server, and can hold the same values as the “code” argument of close().  The “reason” field is a string describing the circumstances of the “close” event.  The “wasClean” field is a boolean value which indicates whether or not the connection was closed cleanly.  Under normal circumstances, “wasClean” is true.  An example “onclose” event handler is shown below.

socket.onclose = function(event) {
  var code = event.code;
  var reason = event.reason;
  var wasClean = event.wasClean;
  // handle close event
};

The following example implements the same “onclose” event handler using the addEventListener() syntax.

socket.addEventListener("close", function(event) {
  var code = event.code;
  var reason = event.reason;
  var wasClean = event.wasClean;
  // handle close event
});

onerror

When a WebSocket encounters a problem, its “onerror” event handler is called.  The event passed to the handler is a standard error object including “name” and “message” fields.

socket.onerror = function(event) {
  // handle error event
};

An equivalent “onerror” event handler which uses the addEventListener() method is shown below.

socket.addEventListener("error", function(event) {
  // handle error event
});

Sending Data

WebSockets transmit data via the send() method.  The send() method comes in three flavors ― one for sending UTF-8 text data, a second for sending ArrayBuffers, and a third for sending blobs.  All three versions of send() take a single argument which represents the data to be transmitted.  The syntax for send() is shown below.

send( data )

When send() is called, the “data” argument is placed in an outgoing buffer.  However, the data may or may not be sent immediately.  To check the number of bytes in the outgoing buffer, use the “bufferedAmount” property.  The following example attempts to send a large ArrayBuffer.  The code checks if the message was sent by inspecting the value of “bufferedAmount”.  A value of zero indicates that the entire ArrayBuffer was sent successfully.

var data = new ArrayBuffer(10000000);

// perform some operations on the ArrayBuffer
socket.send(data);

if (socket.bufferedAmount === 0) {
  // the data sent
}
else {
  // the data did not send
}

Getting Started

In order to start using WebSockets, you will need access to a server that supports the WebSockets protocol.  WebSockets are not subjected to the same origin policy, and therefore you can use any publicly available servers to test your code.  Eventually, however, you will probably need to write your own custom server.  I have written a tutorial for setting up your own Node.js WebSocket server.  A second tutorial is also available for writing the corresponding client code.

Things to Remember

  • WebSockets attempt to connect to their URL immediately upon creation.
  • The “readyState” property can be used to check the status of a connection.
  • Use addEventListener() to attach event handlers.
  • WebSockets receive data via the “message” event.
  • When receiving binary data, the “binaryType” field should be set appropriately.
  • WebSockets send UTF-8 text and binary data using the send() method.
  • The close() method is used to terminate a WebSocket connection.


5 thoughts on “How to Use WebSockets

  1. Web sockets are definitely a development to keep a look out for. What do you think about the connection limitation inferred under HTTP 1.1 specification? What workaround do you prefer?

    • Are you referring to the maximum simultaneous connections per host? If so, you could probably setup subdomains since WebSockets aren’t subject to the same origin policy.

  2. if you can make a video tutorial for that it will be a big helpfull or link us a video tutorial any if you know, anything else..thanx a lot, now am kind like start getting it..