Treehouse

WebSocket and Socket.IO

By on  

WebSocket Socket.IO

My favorite web technology is quickly becoming the WebSocket API. WebSocket provides a welcomed alternative to the AJAX technologies we've been making use of over the past few years. This new API provides a method to push messages from client to server efficiently and with a simple syntax. Let's take a look at the HTML5 WebSocket API: its use on the client side, server side, and an outstanding wrapper API called Socket.IO.

What is the WebSocket API?

The WebSocket API is the next generation method of asynchronous communication from client to server. Communication takes place over single TCP socket using the ws (unsecure) or wss (secure) protocol and can be used by any client or server application. WebSocket is currently being standardized by the W3C. WebSocket is currently implemented in Firefox 4, Chrome 4, Opera 10.70, and Safari 5.

What's great about the WebSocket API that server and client can push messages to each other at any given time. WebSocket is not limited in its nature the way that AJAX (or XHR) is; AJAX technologies require a request to be made by the client, whereas WebSocket servers and clients can push each other messages. XHR is also limited by domain; the WebSocket API allows cross-domain messaging with no fuss.

AJAX technology was a clever usage of a feature not designed to be used the way it is today. WebSocket was created for the specific purpose of bi-direction message pushing.

WebSocket API Usage

Focusing on the client side API only (because each server side language will have its own API), the following snippet opens a connection, creates event listeners for connect, disconnect, and message events, sends a message back to the server, and closes the connection.

// Create a socket instance
var socket = new WebSocket('ws://localhost:8080');

// Open the socket
socket.onopen = function(event) {
	
	// Send an initial message
	socket.send('I am the client and I\'m listening!');
	
	// Listen for messages
	socket.onmessage = function(event) {
		console.log('Client received a message',event);
	};
	
	// Listen for socket closes
	socket.onclose = function(event) {
		console.log('Client notified socket has closed',event);
	};
	
	// To close the socket....
	//socket.close()
	
};

Let's take a look at the individual pieces of the snippet above. The argument provided to WebSocket represents the URL to the address listening for socket connections. onopen, onclose, and onmessage methods connect you to events on the socket instance. Each of these methods provides an event which gives insight as to the state of the socket.

The onmessage event provides a data property which contains the body of the message. The message body must be a string, so serialization/deserialization strategies will be needed to pass more data.

The syntax is extremely simple which makes using WebSockets incredibly easy...unless the client doesn't support WebSocket. Internet Explorer does not currently support WebSocket. There are a few fallback transports that you can use if the client doesn't support WebSocket:

  • Flash - Flash can provide a simple alternative. The obvious drawback is that Flash is not installed on all clients, and in the case of the iPhone/iPad, cannot be.
  • AJAX Long-Polling - AJAX long-polling has been used for quite a while to simulate WebSocket. It's a technology that works but isn't optimized for message sending. I wouldn't call AJAX long-polling a hack but it's simply not an optimal method.

Wouldn't it be great if an API was available that would provide WebSocket event handling, fallback transports, and a server side solution, all within one API? Luckily Guillermo Rauch has created Socket.IO.

WebSocket with Socket.IO

Socket.IO is a WebSocket API created by Guillermo Rauch, CTO of LearnBoost and lead scientist of LearnBoost Labs. Socket.IO will use feature detection to decide if the connection will be established with WebSocket, AJAX long polling, Flash, etc., making creating realtime apps that work everywhere a snap. Socket.IO also provides an API for Node.js which looks very much like the client side API.

Client - Socket.IO Setup

Socket.IO is available for download at GitHub. You can include the socket.io.js file or you can pull Socket.IO from CDN:

<script src="http://cdn.socket.io/stable/socket.io.js"></script>

With Socket.IO available in the page, it's time to create a Socket:

// Create SocketIO instance, connect
var socket = new io.Socket('localhost',{
	port: 8080
});
socket.connect(); 

// Add a connect listener
socket.on('connect',function() {
	console.log('Client has connected to the server!');
});
// Add a connect listener
socket.on('message',function(data) {
	console.log('Received a message from the server!',data);
});
// Add a disconnect listener
socket.on('disconnect',function() {
	console.log('The client has disconnected!');
});

// Sends a message to the server via sockets
function sendMessageToServer(message) {
	socket.send(message);
}

Socket.IO simplifies the WebSocket API and unifies the APIs of its fallback transports. Transports include:

  • WebSocket
  • Flash Socket
  • AJAX long-polling
  • AJAX multipart streaming
  • IFrame
  • JSONP polling

You may set any of the Socket.IO instance's options with a second argument to the constructor. Options include:

  • port - the port to connect to
  • transports - an array containing the different transport types in order by preference []
  • transportOptions - an object with additional properties to pass to the transport

Socket.IO also provides the usual connect, disconnect, and message events that the native WebSocket API provides. Socket also provides an on method which wraps each event type, much the way Node does.

Node.js - Socket.IO Setup

The server side solution provided by Socket.IO allows unification of the client and server side APIs. With Node, you create a typical HTTP server but then pass the server instance to SocketIO. From there, you create connection, disconnect, and message listeners much the way you did on the client side.

A sample server side script would look very much like this:

// Require HTTP module (to start server) and Socket.IO
var http = require('http'), io = require('socket.io');

// Start the server at port 8080
var server = http.createServer(function(req, res){ 

	// Send HTML headers and message
	res.writeHead(200,{ 'Content-Type': 'text/html' }); 
	res.end('<h1>Hello Socket Lover!</h1>');
});
server.listen(8080);

// Create a Socket.IO instance, passing it our server
var socket = io.listen(server);

// Add a connect listener
socket.on('connection', function(client){ 
	
	// Success!  Now listen to messages to be received
	client.on('message',function(event){ 
		console.log('Received message from client!',event);
	});
	client.on('disconnect',function(){
		clearInterval(interval);
		console.log('Server has disconnected');
	});

});

You can run the server portion (assuming you have Node.js installed) from command line with:

node socket-server.js

Now your client and server can push messages back and forth! Within the Node.js script, you can create a periodical message sender using some simple JavaScript:

// Create periodical which ends a message to the client every 5 seconds
var interval = setInterval(function() {
	client.send('This is a message from the server!  ' + new Date().getTime());
},5000);

The server side script will push a message to the client every five seconds!

dojox.Socket and Socket.IO

Persevere creator Kris Zyp has created dojox.Socket. dojox.Socket wraps the WebSocket API in an API consistent with Dojo and provides a long-polling alternative if the client doesn't support WebSocket. Here's how you can use dojox.Socket on the client side and Socket.IO on the server side:

var args, ws = typeof WebSocket != 'undefined';
var socket = dojox.socket(args = {
	url: ws ? '/socket.io/websocket' : '/socket.io/xhr-polling',
	headers:{
		'Content-Type':'application/x-www-urlencoded'
	},
	transport: function(args, message){
		args.content = message; // use URL-encoding to send the message instead of a raw body
		dojo.xhrPost(args);
	};
});
var sessionId;
socket.on('message', function(){
	if (!sessionId){
		sessionId = message;
		args.url += '/' + sessionId;
	}else if(message.substr(0, 3) == '~h~'){
		// a heartbeat
	}
});

dojox.socket.Reconnect has also been created to automatically reconnect if the socket loses connection. Look forward to dojox.Socket debuting in Dojo 1.6.

Practical Applications

There are many practical applications for WebSocket. WebSocket is ideal for most client-to-server asynchronous purposes, chat within the browser being the most prominent. WebSocket is used to day by most many companies because of its efficiency. Socket.IO is in use by many organizations and was very popular at the Node KnockOut contest.

WebSocket Resources

There's not a great deal of information available about WebSocket so I've rounded up a few helpful resources:

Take a moment to download my demo and visit the resources provided above. The WebSocket API is the future of asynchronous messaging; Socket.IO is the best available resource for WebSocket in Node.js and within the browser. Let me know your thoughts on WebSocket as I'm curious to know if you're as excited as I am by this new API!

ydkjs-1.png

Recent Features

Incredible Demos

  • Making the Firefox Logo from&nbsp;HTML

    When each new t-shirt means staving off laundry for yet another day, swag quickly becomes the most coveted perk at any tech company. Mozilla WebDev had pretty much everything going for it: brilliant people, interesting problems, awesome office. Everything except a t-shirt. That had to change. The basic...

  • Google Extension Effect with CSS or jQuery or MooTools&nbsp;JavaScript

    Both of the two great browser vendors, Google and Mozilla, have Extensions pages that utilize simple but classy animation effects to enhance the page. One of the extensions used by Google is a basic margin-top animation to switch between two panes: a graphic pane...

Discussion

  1. Ian

    WebSocket is one of those things that looks fascinating but I just don’t know much about. I’m not the best Javascript developer, but I want to learn more about API. I’m really interested in how to utilize it from the backend. Thanks for the roundup of resources, I’ve bookmarked some of them!

  2. Christian Wisniewski

    Great article!
    Have been already thinking while this came out to use it for a Chat on a small communitysite i’m making.

    Just one little note: You shouldn’t note that Flash would be an alternative and it wouldn’t work on iPhones/iPads, since they are using Mobile Safari which will actually let this API work even without Flash ;)

    Hope to read more stuff about that soon, maybe some code examples for a chat ;)

  3. Tim

    Socket.io and nodejs are both genius, though I can’t seem to come up with a usecase for it other than a chatbox or a feedback-system for clients.
    It’s like thinking the other way around with the server-side scripting to it. Maybe that’s why i’m lacking inspiration of thinking about something really cool.

    Javascript is about thinking out of the box, so this is yet another box to overcome ;-)

    • Think about Google Wave, Twitter, Google Docs, Facebook Wall any other collaborative application that multiple users use at the same time. You can also think of an alert system that runs in your browser, say watching if you received any new messages or mail.

      Btw, there will be no Opera 10.70 only Opera 11.

    • Any application would benefit from this technology, we use Ajax to reduce the clunkiness of our applications through reduced page reloads and as David points out in the article XHR was never really built for what it has been spawned into. Websockets will help bring the desktop application feel into the browser. Really exciting stuff!

    • The use cases are many! For example, a web application that monitors tasks and resources on a server-side application. Or really any kind of application that you might want to view continuously updated information for.

      Anybody who doesn’t see the use case may not be doing any sort of polling with AJAX. If you’ve ever set a polling interval to retrieve information, you can instantly see how WebSocket will make this job a lot easier, more interactive, and more elegant. :-)

      Too bad it’s been yanked from Fx4 and Opera for now… looking forward to its happy return.

    • Another us is for multi-player games.

  4. I needed to wait until I got my desktop before I got into AJAX….now this looks amazing. If there are enough resources on it, I’ll spend my time on this instead of AJAX since it looks to be even more amazing.

  5. Nice article.

    I’ve written about the problems with WebSocket before – http://blog.caplin.com/2010/03/02/why-we-dont-need-html5-websocket/

    Something I didn’t touch on in that post though, and something I brought up a couple of times early on in the WebSocket mailing lists was server API..

    Everyone wants to wrap up WebSocket because of various issues with it, so you can have fallback mechanisms. The client end of WebSocket has a well defined API, so implementing fallback mechanisms behind this (or a similar API) is very easy. On the server side there is no API, just the raw protocol to implement. There is no CGI API, no servlet API, nothing to give any reuse or commonality for implementing the server end of a WebSocket application.

  6. Thanks David, i have been using Ajax timeouts for a two-player online game and i think webSockets would be perfect for my application.

  7. For the WebSockets server to work with the Flash-based fallback, isn’t it also necessary to add a crossdomain.xml file in the root folder, available via port 843? I’m pretty sure it is.

    <?xml version="1.0"?>
    <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
    <cross-domain-policy>
    
 <allow-access-from domain="*" to-ports="*"/>

    </cross-domain-policy>

  8. @mathias bynens – socket-io-server (developed by the same guys) handles this flash crossdomain.xml issue for you.

  9. I’ve installed Node and Socket.io on a Ubuntu VM and was unable to get David’s sample code to connect to the server. I resolved this by changing socket-client.html:

    var socket = new io.Socket(localhost, {port: 8080, rememberTransport: false});
    to:
    var socket = new io.Socket(null, {port: 8080, rememberTransport: false});

    I discovered this after looking at the socket.io/example/chat.html file.

    I hope this is helpful to someone else.

    Neville

  10. Looks like you had some serious fun with the bling on your site. I agree with the first sentence. Websockets, and the interim fall back solutions that can be done transparently, are incredibly exciting. It’s been over 10 years in coming, but it’s really gonna happen now.

  11. Really great article David, super helpful!

    You may want to update how to include the socket.io.js file for the client. The CDN points to version 0.6.0 which is missing a number of features, namely the connecting and connect_failed events. which are pretty helpful. Those events are in v0.6.2. Took some digging around before I noticed the previous version on the CDN.

  12. Luiz Carlos

    info – unhandled socket.io url

    in terminal

    solution ?

    • Carlton Dickson

      I had a similar problem and I think this was due to the fact I was pointing to a JS file at http://cdn.socket.io/stable/socket.io.js, but this is for socket.io 0.6.

      Turns out that if your node server is up and running with the code shown at “NodeJS – Socket.IO Setup”, you should be able to access something like http://localhost:12345/socket.io/socket.io.js and you will see the JS being served up from there and that’s what you need to point at.

      Now when I start up my server I only see…

      “info – socket.io started”

      Also another line has changed slightly

      var socket = new io.Socket(‘localhost’,{
      port: 8080
      });
      socket.connect();

      can be written as…

      var socket = io.connect(‘http://localhost:12345′);

      Nice tutorial but think it’s out of date which led to a lot of headbanging this evening :)

  13. Sergio

    Good article.

    I’m absolutely new to websockets. Still I’m reading lot of blogs about node.js, websockets, html5… all of them are using localhost servers.

    Comparing websockets to a classical AJAX POST, websockets needs to know always server IP or name address. Which is the way to solve this using websockets?
    BR,
    Sergio

  14. Joes

    Ahem, if this article talks about websockets, where’s SockJS review?

  15. Akash Saikia

    Nice article and got a kick start to work with Socket.IO :)
    Thanks.

  16. Hi! I just wanna ask how the code will change if it is to be uploaded in the net. I am quite aware that you should change localhost to your domain name but whenever I upload it and access it through http://domainname:8080 it doesn’t seem to work. Any ideas?

  17. Matt

    Just wondering if I can connect to a websocket in native swf (i.e not embedded in a html page at all): this is due to it being a stagecraft os for a set top box.
    thanks in advance.
    mk

  18. Some ideas for this technology.

    http://195.234.11.44/playground/node/

  19. Heads up, that CDN link is serving up an extremely outdated version of client socket.io.

  20. Here is a example of socket.io and HTML5 Canvas app from Node js.

    http://drawme.jit.su

  21. danilo di moia

    Nice tutorial, but be careful to change


    var socket = io.connect('http://your.domain.name:8080');

    on socket-client.html to make it work with socket.io newer version.

  22. Panos Papadopoulos

    I think there is an error in the comment of the last code snippet of “Node.js – Socket.IO Setup” section:

    // Create periodical which ends a message to the client every 5 seconds

    must be:

    // Create periodical which sends a message to the client every 5 seconds

    The word “ends” must be “sends”.

  23. Abhishek Kaushik

    I want to create an online auction for a virtual cricket league. There would be some 5-6 teams siitting on their comp, all the comp would be connected through LAN wires. I want to make my comp as server where i would run server using node.js. At an interval of 5 min a player will appear and teams have to enter there bid. At last whoever throws highest bid would take the player. These are my plan.
    Can someone help me, in what way I should start? How should i proceed. I just want approach.
    Thanks in advance!

  24. There is also, SocketCluster ( https://github.com/topcloud/socketcluster ) – It’ similar to Socket.io but with a focus on high scalability (makes use of all CPU cores to handle as much traffic as possible).

  25. chalama

    How to do automation on WebSocket API?

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!