WebSockets are a part of the HTML5 specification, and the simplest way of looking at them is that they set a standard for creating long-running bi-directional connections between a browser and a server. With this connection in place, browsers can send messages back to the server (like quicker Ajax) and, even more crucially, the server can push new information to connected clients as it becomes available. WebSockets allow extremely low latency communication with little overhead.
There have been techniques for pushing data to connected clients for many years, and these have been grouped under the term Comet (see en.wikipedia.org/wiki/Comet_(programming) for details). However, WebSockets create a far simpler and standardised way of doing this, and are likely to revolutionise the way that people build real-time interfaces. At this stage, WebSockets are compatible with several modern browsers and there are Flash fallback options available for those that have yet to jump on board.
Why use them? WebSockets enable you to build truly real-time user experiences much more easily. People have already become accustomed to a feeling of immediacy in the applications they use regularly, and want to feel connected to other people using a service. The rise of Facebook chat, multiplayer online games, Twitter’s real-time updates and collaborative editing via Google Docs have paved the way for the applications of the next few years. These types of user experiences are going to grow in popularity, and WebSockets will be the technology behind them. It’s going to become increasingly important to know how to build these sorts of interfaces.
How to use them
So how do we use this awesome new technology? Unlike some of the other parts of the HTML5 spec, WebSockets need both a client and a server component. They’re therefore not as trivial to get up and running as with things like video, canvas, geolocation or form controls. However, don’t let that you put you off, as there are loads of options to get started.The first method available is to install and maintain your own socket server. There are open source projects such as Socket IO, which are fairly easy to get started with. However, it’s not always simple to install these kinds of socket servers in your average hosting environment because of imposed hosting security restrictions and reduced resource allocations for the long-running connections that WebSockets require.
Another option is to use a hosted service that integrates with your existing website infrastructure. This is what my company, Pusher, provides.
For the tutorials, I’ll use our service because the WebSocket API is a bit ‘bare bones’ and an abstraction layer can make the communication between client and server easier to understand.
The abstraction layers can also manage common scenarios such as handling connections being dropped and reconnection, and can add richer features and functionality too. For example, a library that wraps WebSockets can be considered similar to the way jQuery wraps access to basic DOM manipulation; think document.getElementById(“myDiv”) vs. jQuery(“#myDiv”).
What do they look like?
When we say that WebSockets are a part of the HTML5 specification, it isn’t necessarily clear what that means. In practice, this doesn’t mean a change to the HTML of the page, but rather the functionality is exposed via some new JavaScript APIs. The first thing that is new is a WebSocket object that is initialised with the URL it needs to connect to:- var ws = new WebSocket('ws://example.com');
- socket.onopen = function(evt)
- { alert("Connection established")
- }
- socket.onclose = function(evt){
- alert("Connection closed")
- }
- socket.onmessage = function(evt){
- alert("I got data: " + evt.data)
- }
- socket.send( "Have some data" );
Creating a real-time survey
To demonstrate a more detailed use, I’ve taken an example of a real-time survey. If this was a full application, there would probably be several things I’d do differently, but it will allow me to show how WebSockets are useful.In this example, our application asks the simple question ‘What is the best language?’ and provides buttons for the user to make their choice. A graph is displayed above the buttons that tracks the popularity of the various answers. What makes this more interesting is that you can see the results change in real- time as people in other browsers vote.
I'll be using Ruby on the server, and will try to keep things pretty simple so we can focus on the WebSocket interaction. I’ll also use Pusher for the WebSocket server, since it adds fallback support for older browsers. The source code can be found on Github. For those who’d like to start by building the basic application, have a look at the Getting Started section. If you’d rather jump into adding real-time functionality, download the basic application.
Getting started
First, we need to create our basic survey Rails application. We need a database, a SurveyEntry model, a SurveyEntries controller and a view to display results. It’s easy to do this in Ruby on Rails. Open a command prompt or terminal window and enter the following commands:rails new realtime_survey – create the new application
cd realtime_survey – navigate into the new application directory
rake db:create – create the database
rails generate model SurveyEntry choice:string – create the SurveyEntry model
rails generate controller SurveyEntries index create – create the SurveyEntries controller with actions called index and create
rake db:migrate – create the survey_entries table in the database for the SurveyEntry model
An index.html.erb file should have been created within the /app/views/ survey_entries folder. This represents the view for the index action of the SurveyEntries controller. If present, delete the index.html file found within the app/public directory and update the /config/routes.rb so that the index action within the SurveyController is called by default.
- RealtimeSurvey::Application.routes.draw do
- root :to => "survey_entries#index"
- resources :survey_entries
- end
- class SurveyEntry < ActiveRecord::Base
- FORM_OPTIONS = ['ruby', 'php', 'python', 'java', 'other']
- def self.get_results
- counts = SurveyEntry count({ :group => :choice })
- FORM_OPTIONS.map do |o|
- {
- 'title' => o,
- 'votes' => counts[o]||0
- }
- end
- end
- end
- class SurveyEntriesController < ApplicationController
- def index
- @survey_entries = SurveyEntry.get_results
- end
- def create
- SurveyEntry.create(:choice => params[:choice]) redirect_to '/'
- end
- end
To convert the table to a chart we need to add the jQuery library (jquery. com), the jQuery chart plug-in and make a simple call to create the chart to the HTML page:
- <script src="/javascripts/jquery-1.6.1.min.js">script>
- <script src="/javascripts/jquery.charts.js">script>
- <script>
- $(function(){
- $(“#results”).chart();
- });
- script>
- def create
- SurveyEntry.create(:choice => params[:choice])
- redirect_to '/'
- end
Once the record has been saved, the user is redirected to the originating page and the index action. The form submission could also be progressively enhanced using an Ajax request, but standard form submission will do for now. We won’t stop people from voting more than once, but a real application probably would.
Adding real-time updates
We add real-time updates to the application by introducing a WebSocket connection so we can push the survey results from the server to all the connected browsers whenever they change. In this example, we’ll use Pusher for the WebSocket server, because configuring a socket server is rather beyond the scope of this tutorial.Pusher also provides a REST API that allows you to send messages to connected clients from your existing language of choice. However, many of the principles from Pusher can easily be applied to a more generic WebSocket installation. Pusher has free ‘sandbox’ accounts to trial the functionality, so if you feel like trying this example you’ll need to sign up there.
There will be two parts to this WebSocket integration:
- In the client-side code we’ll have to establish a WebSocket connection and listen for messages coming out of it.
- On the server, we’ll have to broadcast new versions of the data when someone makes a change.
Client-side integration
The first thing we need to do is establish a WebSocket connection with the Pusher server. Pusher has a JavaScript library that handles this for you. You just need to include some JavaScript on your page, and create a new Pusher object with your public API key:- <script src="http://js.pusherapp.com/1.8/pusher.min.js">script>
- <script>
- var pusher = new Pusher('YOUR_API_KEY');
- script>
- var myChannel = pusher.subscribe('survey-channel');
Dealing with messages
Pusher wraps messages in a simple JSON protocol that makes them very easy to deal with on the client-side. As we saw earlier, a WebSocket object generally has only one event listener: onMessage and anything beyond a simple application becomes difficult to manage. The following example demonstrates this using a hypothetical scenario where items are added to a list:- var ws = new WebSocket('ws://ws.example.com')
- ws.onMessage(function(data){
- $('#myList').append(data);
- });
We call messages sent to Pusher ‘events’, and they are similar to the evented UI programming you may be familiar with in JavaScript. For example, when a mouse moves it fires a mousemove event with data about the position of the cursor.
With Pusher, when an event happens on your server (eg someone registers a survey entry), this event is broadcast to the connected client (we’ll add this server code later).
You can use your own naming conventions to handle different events. In our example, we’ll be binding to an event called data-changed, which will supply us with new survey results data. It will look like this in our JavaScript:
- myChannel.bind('data-changed', function(data){
- updateResults(data)
- });
- function updateResults(data){
- var tbody = jQuery("#results tbody");
- var html = "";
- for (var i=0; i < data.length; i++) {
- html += "" + data[i].title + "" +
- "" + data[i].votes + "";
- }
- tbody.html(html);
- jQuery(".chartscontainer").remove(); // remove old chart
- jQuery("#results").charts(); // redraw
- }
- function updateResults(data){
- jQuery.noticeAdd({
- text: 'Results updated',
- stay: false
- });
- var tbody = jQuery("#results tbody");
- var html = "";
- for (var i=0; i < data.length; i++) {
- html += "" + data[i].title + "" +
- "" + data[i].votes + "";
- }
- tbody.html(html);
- jQuery(".chartscontainer").remove(); // remove old chart
- jQuery("#results").charts(); // show updated chart
- }
Triggering ‘events’
We now have a way of dealing with new data as it comes in, but we also need to write a little bit of code on our server application that sends it out. Because our application is written in Ruby, we can install the Pusher RubyGem, which will help us with this. There are many libraries in various languages that you can use to communicate with Pusher. In our case, we just need to install the gem using gem install pusher and require it in our code. An easy place to include this is in config/environment.rb, where you can also put in your Pusher credentials:- require 'pusher'
- Pusher.app_id = 'YOUR APP ID'
- Pusher.key = 'YOUR KEY'
- Pusher.secret = 'YOUR SECRET'
- gem ‘pusher’
- def create
- SurveyEntry.create(:choice => params[:choice])
- Pusher['survey-channel'].trigger('data-changed',
- SurveyEntry.get_results.to_json)
- redirect_to '/'
- end
Conclusion
In this tutorial we first created a simple Ruby survey application. We enhanced the basic look and feel of the application through progressive enhancement by applying CSS and a jQuery charting visualisation. We then bettered the user experience further by adding real-time functionality to the application using HTML5 WebSockets and Pusher.I’m sure this tutorial has shown the power of HTML5 WebSockets and how easy it can be to add real-time functionality to any existing app or have real- time enabled in your app from day one. In this tutorial we demonstrated server to client communication and it’s important to remember that WebSockets allow bi-directional communication. I’m really excited about this technology and have already seen loads of great examples of how it can be used (pusher.com/demos), but the technology is still young and I’m convinced that we are going to start to see a new generation of web apps and games powered by HTML5 WebSockets and its bi-direction communication capabilities.
I have seen a extremely informative blog. Truly I like this blog. This blog gives us especially excellent knowledge about web development.
ReplyDeleteAnd your comment gives especially excellent knowledge about SPAM
Delete