You may read that Socket.io falls back gracefully to other communication routes if WebSockets are not available in the browser. Actually, Socket.io does not technically fallback to Ajax (XHR) polling or JSONP if WebSockets are not available in the browser (for a refresher on WebSockets, see this blog post). It first establishes a connection using one of these communication methods before upgrading. From the Socket.io website:

Socket.IO never assumes that WebSocket will just work, because in practice there’s a good chance that it won’t. Instead, it establishes a connection with XHR or JSONP right away, and then attempts to upgrade the connection to WebSocket. Compared to the fallback method which relies on timeouts, this means that none of your users will have a degraded experience.

The great things about socket.io is that it uses a clean syntax to communicate whether or not WebSockets are available and therefore can be used even if all portions of your app do not require real-time communication. The basic setup on a Node.js server using Express could look like this,

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res){
  res.sendfile('index.html');
});

io.on('connection', function(socket){
  console.log('a user connected');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

We initialize socket.io and pass it the http server object. In this way, socket.io is riding on top of the http server. On the client side, taking an example from the socket.io website, we have something like this using some jQuery.

<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
  var socket = io();
  $('form').submit(function(){
    socket.emit('chat message', $('#m').val());
    $('#m').val('');
    return false;
  });
</script>

Back on the server, we listen for the chat message event being sent from the client:

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    console.log('message: ' + msg);
  });
});

This syntax is simple and easy to understand. The client is emitting a message, in this case a string of text (but it could also be binary data, check out socket.io-stream for more on this) with the event chat message and the server listens for that event with socket.on('chat message'....

Now, if WebSockets are not available, socket.io will use AJAX (XHR) long-polling requests to accomplish the same thing but without you having to write different code. This is incredibly powerful since the developer no longer needs to worry about writing code for fallbacks.

Things to be aware of with XHR long-polling

One thing you should be aware of is that XHR long-polling does not handle a dropped connection very well. Let's say you were driving in a car and on your laptop using a 4G mobile hotspot (not driving of course) and the car went through an area of poor service and the connection is lost, even momentarily. The client may or may not be able to detect that the connection was lost. XHR error handling mechanisms don't work very well in this situation and the client may leave the connection open even though it's been dropped on the server side.