Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / HTML5, CSS3, and JavaScript /

Real-time data exchange in HTML5 with WebSockets

by Ryan Stewart

Ryan Stewart
  • blog.digitalbackcountry.com

Content

  • Using WebSockets
  • Connecting to a WebSocket server
  • Managing data
  • Going binary
  • Where to go from here

Created

27 February 2012

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
HTML5

Requirements

User level

Intermediate

Sample files

  • realtime_data_in_html5_with_websockets.zip

The WebSocket API is one of the more powerful new features in the HTML5 specification because it opens the door to real-time communication and pushing messages.

This article describes a basic chat program that shows the basics of WebSockets and how to implement them on the client side.

Using WebSockets

The WebSocket API has been somewhat volatile over the past year as the W3C specification has been solidified. It has finally been completed and the specification can now be implemented consistently across browsers.

Why use WebSockets?

Instead of using the HTTP protocol, WebSockets use their own protocol. There is a significant amount of overhead incurred whenever communication over HTTP happens. Because of the request/response mechanism and all of the information that HTTP stores in header information, exchanging even basic information can result in lots of data being sent back and forth.

WebSockets, by contrast, are full duplex, which means they can communicate back and forth at the same time without the request/response overhead. The header information is also much smaller, so the bulk of the data being exchanged is the actual data from the application.

Browser support for WebSockets

Most of the major browsers now support some version of WebSockets. Firefox, Chrome, and the latest version of Internet Explorer all have added support for the WebSocket API. Safari and Opera offer partial support for the API.

One of the major issues is understanding which draft of the WebSocket spec is supported by the browsers. Wikipedia has a good entry that lists the specifications by version number and which browser versions support them; for details, visit http://en.wikipedia.org/wiki/WebSocket#Browser_support. Going forward, the final version of the specification, RFC 6455, is the one that will be implemented.

Setting up a server

When working with WebSockets, you need to have a server that supports them. Complete instructions for configuring a server that adheres to the WebSockets specification are beyond the scope of this article, but it's an important enough topic to address at least briefly. There are a few different ways to potentially implement WebSockets.

PHP ships with built-in support for WebSockets, so you could write your own PHP socket server that handles the requests and responses from the client code. There are also Java and Ruby projects that provide WebSocket support for those languages.

One of the more interesting ways to get up and running is a project called Socket.io that runs on Node.js. It has server-side and client-side libraries that make using WebSockets very easy. Node.js lets you use JavaScript on the server so the client- and server-side languages can be the same. For basic socket testing, websocket.org hosts a test server at http://websocket.org/echo.html that will simply send the transmitted data as a response back to the client.

The server I use comes from Kevin Hoyt who wrote a socket server using Adobe AIR. For details, see the AIRWebSocket project on Github.

Connecting to a WebSocket server

The core of the WebSocket API is the WebSocket class, which provides the methods and events that handle all of the communication with the server.

It is important to have your code first check that the browser supports WebSockets. The quickest way to do this is to see if window.WebSocket exists. A more powerful solution is to use the Modernizr library, which helps detect support for WebSockets while providing a graceful fallback for older browsers.

The example chat application provides a Connect button that the user can use to initiate the connection to the socket server. This process is implemented in a connect() function:

var connection = {}; function connect() { if(window.WebSocket != undefined) { if(connection.readyState === undefined || connection.readyState > 1) { connection = new WebSocket('ws://localhost:1740'); } } }

The first line of code above defines the connection object that will be used by the rest of the application. When you make it a global variable, the connection object can be used in other functions. After checking to make sure that the browser supports WebSockets, the code checks to make sure there isn't already a connection active.

The WebSocket object provides a readyState property that indicates the connection's ready status. The values are as follows:

const unsigned short CONNECTING = 0; const unsigned short OPEN = 1; const unsigned short CLOSING = 2; const unsigned short CLOSED = 3;

As long as the readyState is greater than 1, the connection isn't open so the application can connect to the socket server.

Connecting to the server is just a matter of instantiating the WebSocket class and passing in the URL and port number of the socket server. The browser then makes a connection with the server.

Handling the WebSocket object in Firefox

The WebKit browsers and Opera handle WebSockets in the same way, but in Firefox the WebSocket object has a prefix; it is referred to as MozWebSocket . Beyond that, the APIs are the same, so an easy way to keep everything simple is to check for the existence of window.MozWebSocket and then set it to the regular WebSocket object.

if (window.MozWebSocket) { window.WebSocket = window.MozWebSocket; }

The open event

If the connection is successful, the browser will fire an open event. To make sure this gets caught, the WebSocket API includes an onopen property, which is assigned to a function that will run code for every open event.

The code below sets the onopen property to a corresponding onopen() function that sets a couple of variables so that the UI is updated to indicate that the user is logged in.

connection.onopen = onopen;

Here is the onopen() function:

function onopen (event) { document.getElementById('connected').innerHTML = "Connected"; document.getElementById('chat').innerHTML = "You have joined the chat<br />"; }

Note that most people don't actually assign those methods to named functions but rather include them in anonymous functions right where they are first defined. I have implemented it this way because I like having the separation, but it may seem a bit redundant to you as you dig into more WebSocket examples.

Managing data

Now that your client is connected you can start dealing with actual chat messages. The server I have set up for the moment just cycles through all of the currently connected users whenever it gets a message and then sends that message out to all of those users. Though it is a pretty basic chat server, it illustrates many key WebSocket concepts.

Sending messages

With WebSockets you can send text, or UTF-8 data, as well as binary data such as pictures or videos. They both use the same API on the client side, but it will largely depend on the server to actually handle the data types correctly.

To send a message to the socket server the chat application simply invokes the send() method of the connection object. It takes a single parameter, the message being sent, which it passes to the socket server.

When the user clicks on the Send Message button in the chat application, the sendmessage() method sends the message typed by the user along with the username. The socket server will then loop through all the clients, including the sender, and deliver the message to them.

function sendmessage() { var messagetext = document.getElementById('chatmessage').value; messagetext = username + ": " + messagetext; connection.send(messagetext); }

Receiving messages

To handle incoming messages, the WebSocket API uses the onmessage property of the connection event. Just like the onopen property covered earlier, this property takes a function that will be called whenever a new message arrives. So the first step is to set up the event handler in the original connect() method right before the onopen definition:

connection.onmessage = onmessage;

Once that is set up, define the onmessage() function:

function onmessage (event) { var chatdiv = document.getElementById('chat'); chatdiv.innerHTML = chatdiv.innerHTML + event.data + "<br />"; }

The event that is received by onmessage is of type MessageEvent . It includes a data property that has the value of the message being received. In this case, that is used to display the chat text. This data property includes the username of the chat participant along with the message they sent. This value is appended to the chat div window.

Handling errors

Error handling is an important topic to cover, even if only quickly. Along with onopen and onmessage, the WebSocket API also includes an onerror property, which takes a function that runs any time an error occurs. The error event includes a data property that provides some information about the error.

Here is the basic error handler used in the chat application:

function onerror(event) { console.log(event); document.getElementById('chat').innerHTML = "There was an error: " + event.data; }

Going binary

By enabling the exchange of real-time data, the WebSocket API opens some interesting possibilities when combined with the rest of the host of new HTML5, JavaScript, and CSS3 features.

One of the cooler demos I've seen is a collaborative whiteboard using the canvas element. Every time someone connected to the socket draws on it, a message gets sent out to the connected clients so everyone can see what is being drawn. It's a neat idea, but all that's really happening under the hood is that the socket server and application are exchanging a set of x and y coordinates in text.

To illustrate the binary capabilities of the WebSocket API, I implemented a similar application that uses binary data. Specifically, I implemented a quick canvas painting feature that the user can use to draw something on a small canvas area. When the user clicks a button, the application does not send a set of coordinates to the socket server, but rather takes a snapshot of the image and sends it as binary data to the socket server. The socket server sends the data back as an image, which will appear in the chat window of all connected clients. This demo will only work in the latest version of Chrome because binary WebSocket support is still somewhat on the cutting edge.

Creating binary data

To send and receive binary data correctly you need to set up a binaryType for the WebSocket API. The binaryType can be either arraybuffer or blob , which are the two basic binary types that JavaScript supports. You can use either one depending on what you're sending and how you want to access it. I found arraybuffer to be ideal for this example because it's easy to iterate through an array, and I found that I had to copy a lot of data back and forth between arrays. So the WebSocket setup code becomes this:

connection = new WebSocket('ws://localhost:1740'); connection.binaryType = "arraybuffer"; connection.onopen = onopen; connection.onmessage = onmessage; connection.onclose = onclose; connection.onerror = onerror;

Now you need to get binary data out of the canvas. I wrote a sendphoto() method that does the work of pulling the binary data out of the canvas element on the page. It uses the getImageData() method to get the actual binary array data and then it loops through the data and inserts it into a Uint8Array. The code accesses the buffer property of this array and sends it using the WebSocket API.

function sendphoto() { imagedata = context.getImageData(0, 0, imagewidth,imageheight); var canvaspixelarray = imagedata.data; var canvaspixellen = canvaspixelarray.length; var bytearray = new Uint8Array(canvaspixellen); for (var i=0;i<canvaspixellen;++i) { bytearray[i] = canvaspixelarray[i]; } connection.send(bytearray.buffer); context.fillStyle = '#ffffff'; context.fillRect(0, 0, imagewidth,imageheight); }

That data goes to the socket server and the socket server sends the binary data back out to all of the connected clients. If you're interested in seeing how the server does that, you can take a look at the Github project for the code.

Receiving a binary message

To handle incoming binary messages, you'll need to modify the onmessage() function. Because you'll have to handle two types of data, the ArrayBuffer and the String data, you'll want to check the instanceof property of event.data and route the data accordingly.

Once you do that, the process will be to translate the ArrayBuffer data into a typed JavaScript array. Then, create a temporary Canvas element that is used to insert the ArrayBuffer data by manipulating the image data of the canvas. Finally, with the image stored in the temporary canvas, use the toDataURL() method to get a URL string that you can set as the source of an img element, which then gets displayed on the screen.

if(event.data instanceof ArrayBuffer) { var bytearray = new Uint8Array(event.data); var tempcanvas = document.createElement('canvas'); tempcanvas.height = imageheight; tempcanvas.width = imagewidth; var tempcontext = tempcanvas.getContext('2d'); var imgdata = tempcontext.getImageData(0,0,imagewidth,imageheight); var imgdatalen = imgdata.data.length; for(var i=8;i<imgdatalen;i++) { imgdata.data[i] = bytearray[i]; } tempcontext.putImageData(imgdata,0,0); var img = document.createElement('img'); img.height = imageheight; img.width = imagewidth; img.src = tempcanvas.toDataURL(); chatdiv.appendChild(img); chatdiv.innerHTML = chatdiv.innerHTML + "<br />"; }

And with that, you're sending and receiving text and binary messages with the WebSocket API.

Where to go from here

This tutorial provided an introduction to the WebSocket API and how to use it. Even though the API itself is pretty straightforward, there are a surprising number of great uses for it. Everything from basic chat to real-time games or enterprise dashboards that need real-time data can all rely on the WebSocket API for their communications.

Mozilla's Developer Network has some great content on WebSockets that applies to both WebKit and Firefox; visit https://developer.mozilla.org/en/WebSockets for details. Also take a look at Socket.io, which is great way to get started with WebSockets without having to write much code on the server to make the connections happen.

Explore the sample files for this article for the client-side source code. You'll need both it and the AIR-based socket server from Github to get the application to work. The client-side code by itself should give you a good idea of how to use the WebSocket API for any socket server that supports binary data.

Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License+Adobe Commercial Rights

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.

More Like This

  • Using the Geolocation API
  • CSS3 basics
  • Developing HTML5 games with Impact JavaScript game engine and Dreamweaver CS5.5
  • Introducing the HTML5 storage APIs
  • Introducing theexpressiveweb.com beta
  • Adobe, standards, and HTML5
  • Backbone.js Wine Cellar tutorial – Part 1: Getting started
  • Object types in JavaScript
  • Pseudo-classical object-oriented programming in JavaScript with Minion
  • Backbone.js Wine Cellar tutorial – Part 2: CRUD

Products

  • Acrobat
  • Creative Cloud
  • Creative Suite
  • Digital Marketing Suite
  • Digital Publishing Suite
  • Elements
  • Mobile Apps
  • Photoshop
  • Touch Apps
  • Student and Teacher Editions

Solutions

  • Digital marketing
  • Digital media
  • Web Experience Management

Industries

  • Education
  • Financial services
  • Government

Help

  • Product help centers
  • Orders and returns
  • Downloading and installing
  • My Adobe

Learning

  • Adobe Developer Connection
  • Adobe TV
  • Training and certification
  • Forums
  • Design Center

Ways to buy

  • For personal and home office
  • For students, educators, and staff
  • For small and medium businesses
  • For businesses, schools, and government
  • Special offers

Downloads

  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy Policy and Cookies (Updated)

Ad Choices

Reviewed by TRUSTe: site privacy statement