Email:
NEW! The long-awaited Socket.IO 0.7 has been released. Read the announcement! or the migration guide.
Socket.IO 0.7 released
By Guillermo Rauch - June 21, 2011

After a month under heavy development, Socket.IO 0.7 is finally here!

Socket.IO came out almost a year ago making the first solid steps in the cross-browser realtime space. Ever since then, a constant stream of feedback and support has made this release possible, the biggest yet, with dozens of improvements and bugfixes.

The project so far
  • +1000 Google Groups members
  • +1600 GitHub followers
  • +50 projects in the ecosystem
  • +5 conference talks and meetups
  • +5 language implementations
One socket is cool. You know what's cooler? >1 socket.

Socket.IO 0.7 addresses a major shortcoming of the WebSocket protocol. When you initialize a `WebSocket` in a browser, that one socket can only stream data for a single protocol or purpose, unless you build in logic to channel messages:

var a = new WebSocket();

a.onmessage = function (msg) {
  var msg = JSON.parse(msg);
  if (msg.type == 'chat') {
    Chat.handle(msg.data);
  } else {
    // do something else
  }
};

This presents a number of problems

  1. You need to think about how you encode and interpret messages.
  2. It's hard to achieve interoperability with 3rd-party code.
  3. Logic for "connecting" or "disconnecting" specific parts of the application are inexistent.
  4. Authentication, error-handling for different subsets of functionality introduce even more difficulties.

To fix this, Socket.IO now gives you one `Socket` per namespace you define:

<script>
  var chat = io.connect('/chat');
  chat.on('message', function () {
    // chat socket messages
  });
  chat.on('disconnect', function () {
    // chat disconnect event
  });

  var news = io.connect('/news');
  news.on('item', function () {
    // a new `news` socket event is here
  });
</script>

Each "sub-socket" or "namespace" has the same characteristics of any other Socket, but socket.io does the heavylifting of splitting the messages in a very lightweight and performant way. This technique is specially necessary for non-WebSocket transports, as they're usually associated with more than one connection.

`socket.on('item')` you say?

In my previous example I used a custom event. Custom events allow you to simplify your code, and their implementation adds no overhead to the protocol. This means that if you don't use them, not much will change.

// server-side
io.sockets.on('connection', function (socket) {
  // send custom events to browser socket
  socket.emit('hi', { 'i can send': 'json!' });
});

If you pass parameters, those will be automatically encoded and decoded in JSON for you. In addition, you can pass data around:

// client-side
var socket = io.connect();
socket.emit('set nickname', 'john', function (response) [
  console.log(response);
});

// server-side
// …
socket.on('set nickname', function (nick, fn) {
  if (nick == 'rauchg') {
    fn({ err: 'nickname in use' });
  }
});

The regular `.send` method got simple acknowledgements as well. These are sent if you pass a function as the second parameter:

var socket = io.connect();
socket.send('woot', function () {
  // now i know my message arrived!
});
Volatile messages

Another introduction to the API was the concept of `flags`. Flags are getters that you prefix to the `.send` and `.emit` calls. One of them is `volatile`, which allows you to send messages at a rate that your client can consume them, dropping messages that cannot be flushed out fast enough.

This is very useful for games, high-volume twitter streams, etc.

io.sockets.on('connection', function (socket) {
  setInterval(function () {
    getTweet(function (tweet) {
      socket.volatile.emit('tweet', tweet);
    });
  }, 100);
});
Rooms

Sometimes you want to put a bunch of sockets in one room, and send a message to them. You can leverage rooms by calling `join` on a socket, and then with the flags `to` and `in`:

io.sockets.on('connection', function (socket) {
  socket.join('a room');
  socket.broadcast.to('a room').send('im here');
  io.sockets.in('some other room').emit('hi');
});
A Socket.IO Protocol

Socket.IO caught the attention of people inside and outside of the Node.JS world.

As a result, I created the socket.io-spec project to explain the internals of how the project works, and how the client and server talk to each other

Some changes to the protocol include:

  • The protocol has been made more lightweight, more consistent and a concept of revisions have been introduced to ensure compatibility between clients and servers.
  • A new handshake mechanism that introduces a lightweight negotation of transports and timeouts. In addition, it allows to get more information about a certain client (like the `User-Agent`) that transports like WebSocket don't send.
  • Disconnection packets (that allow to forcedfully kick out clients)
  • And extended message types to make all the aforementioned features possible.
Testing, code-sharing and more

The Node.JS socket.io server has tripled its number of tests, totaling 160 as I speak. This will help add and maintain high levels of reliability.

More interestingly, the new `socket.io-client` has been designed to run both on the client and the server with the same codebase. I wrote a custom test runner that allows the following to be possible:

When the tests are run from the command line, the transports run on Node.JS. In some cases, almost no code modification is needed. For example, there's a WebSocket client by Peter Griess that simulates the exact same WebSocket API of the browser.

All it took to do this was wrap my client modules like this:

(function (module, io) {
  // my module
})(
    'undefined' == typeof module ? module = {} : module
  , 'undefined' == typeof io ? require('socket.io-client') : io
);

Write once. Run everywhere.

A new message dispatcher

Another major change was the introduction of the concept of message dispatcher adaptors. It's now possible to introduce a custom message queue (like one built with RabbitMQ or Redis) at the socket.io level.

This makes socket.io not dependent on a single process to scale. The introduction of the first of these message adaptors is going to make socket.io more robust, reliable and fault-tolerant.

A blogpost will soon be dedicated entirely to this topic, stay tuned!

New examples

Our signature 10-lines-of-socket.io-code chat example app has been streamlined. It now supports nicknames, and looks better:

And now we get another 15-liner (on each side), this time a bot that joins the #node.js IRC channel and shows what's going on:

Thanks

Special thanks to the following people that made this release possible and awesome with their feedback and contributions:

  • Arnout Kazemier (socket.io contributor)
  • Vladimir Dronnikov (socket.io contributor)
  • TJ Holowaychuk
  • Shripad K
  • Sascha Gehlich
  • Mikeal Rogers

… and many others I'm probably forgeting about.

Future

Many exciting things are still to come. I'm going to make it a priority, now that the major architecture changes are out of the way, to have frequent small releases.

Soon, I'm going to unveil the framework we created at LearnBoost to seamlessly power realtime experiences in web applications created with the Express web framework.

As usual, I welcome everyone to help with bugfixes, documentation and wiki pages on GitHub. Also, don't forget to join our brand-new channel #socket.io on irc.freenode.net.

What is Socket.IO?

Socket.IO aims to make realtime apps possible in every browser and mobile device, blurring the differences between the different transport mechanisms. It's care-free realtime 100% in JavaScript.

Server

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});

Client

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>
How to use
Installing
npm install socket.io

Using with the Express web framework

You can serve normal pages and AJAX requests with Express, and attach your socket.io server:

Server

var app = express.createServer();
  , io = require('socket.io').listen(app);

app.listen(80);

io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});

Client

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>
Sending and receiving events.

Socket.IO allows you to emit and receive custom events. Besides `connect`, `message` and `disconnect`, you can emit custom events:

Server

// note, io.listen() will create a http server for you
var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  io.sockets.emit('this', { will: 'be received by everyone'});

  socket.on('private message', function (from, msg) {
    console.log('I received a private message by ', from, ' saying ', msg);
  });

  socket.on('disconnect', function () {
    sockets.emit('user disconnected');
  });
});
Storing data associated to a client

Sometimes it's necessary to store data associated with a client that's necessary for the duration of the session.

Server

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.on('set nickname', function (name) {
    socket.set('nickname', name, function () {
      socket.emit('ready');
    });
  });

  socket.on('msg', function () {
    socket.get('nickname', function (name) {
      console.log('Chat message by ', name);
    });
  });
});

Client

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>
Restricting yourself to a namespace.

If you have control over all the messages and events emitted for a particular application, using the default / namespace works. If you want to leverage 3rd-party code, or produce code to share with others, socket.io provides a way of namespacing a socket.

This has the benefit of `multiplexing` a single connection. Instead of socket.io using two `WebSocket` connections, it'll use one.

Server

var io = require('socket.io').listen(80);

var chat = io
  .of('/chat');
  .on('connection', function (socket) {
    socket.emit('a message', {
        that: 'only'
      , '/chat': 'will get'
    });
    chat.emit('a message', {
        everyone: 'in'
      , '/chat': 'will get'
    });
  });

var news = io
  .of('/news');
  .on('connection', function (socket) {
    socket.emit('item', { news: 'item' });
  });

Client

<script>
  var chat = io.connect('http://localhost/chat')
    , news = io.connect('http://localhost/news');

  chat.on('connect', function () {
    chat.emit('hi!');
  });

  news.on('news', function () {
    news.emit('woot');
  });
</script>
Sending volatile messages.

Sometimes certain messages can be dropped. Let's say you have an app that shows realtime tweets for the keyword `bieber`.

If a certain client is not ready to receive messages (because of network slowness or other issues, or because he's connected through long polling and is in the middle of a request-response cycle), if he doesn't receive ALL the tweets related to bieber your application won't suffer.

In that case, you might want to send those messages as volatile messages.

Server

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  var tweets = setInterval(function () {
    getBieberTweet(function (tweet) {
      socket.volatile.emit('bieber tweet', tweet);
    });
  }, 100);

  socket.on('disconnect', function () {
    clearInterval(tweets);
  });
});
Sending and getting data (acknowledgements).

Sometimes, you might want to get a callback when the client confirmed the message reception.

To do this, simply pass a function as the last parameter of `.send` or `.emit`. What's more, when you use `.emit`, the acknowledgement is done by you, which means you can also pass data along:

Server

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.on('ferret', function (name, fn) {
    fn('woot');
  });
});

Client

<script>
  var socket = io.connect(); // TIP: .connect with no args does auto-discovery
  socket.on('connection', function () {
    socket.emit('ferret', 'tobi', function (data) {
      console.log(data); // data will be 'woot'
    });
  });
</script>
Broadcasting messages.

To broadcast, simply add a `broadcast` flag to `emit` and `send` method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.

Server

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.broadcast.emit('user connected');
});
Using it just as a cross-browser WebSocket.

If you just want the WebSocket semantics, you can do that too. Simply leverage `send` and listen on the `message` event:

Server

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.on('message', function () { });
  socket.on('disconnect', function () { });
});

Client

<script>
  var socket = io.connect('http://localhost/');
  socket.on('connect', function () {
    socket.send('hi');

    socket.on('message', function (msg) {
      // my msg
    });
  });
</script>
Supported transports

In order to provide realtime connectivity on every browser, Socket.IO selects the most capable transport at runtime, without it affecting the API.

  • WebSocket
  • Adobe® Flash® Socket
  • AJAX long polling
  • AJAX multipart streaming
  • Forever Iframe
  • JSONP Polling
Supported browsers
Desktop
  • Internet Explorer 5.5+
  • Safari 3+
  • Google Chrome 4+
  • Firefox 3+
  • Opera 10.61+
Mobile
  • iPhone Safari
  • iPad Safari
  • iPad Safari
  • Android WebKit
  • WebOs WebKit
FAQ
Does Socket.IO support cross-domain connections?

Absolutely, on every browser!

Why Flash?

Flash is absolutely not requiredfor Socket.IO to function. If Flash is available, it'll be leveraged, as it provides almost the same capabilities as WebSocket. If it's not, the best next transport will be chosen.

I want to host the Socket.IO client myself

If you're not relying on Node.JS serving Socket.IO clientside JavaScript files, make sure you set the `WEB_SOCKET_SWF_LOCATION` right after including socket.io.js with the location of the WebSocketMain.swf

This is required in order for Socket.IO to find the .swf file required for Flash WebSocket.

Why not just call it `WebSocket` if the actual WebSocket is not present and mimick its API?

Socket.IO does more than WebSocket, even if WebSocket is selected as the transport and the user is browsing your website with an ultra modern browser. Certain features like heartbeats, timeouts and disconnection support are vital to realtime applications but are not provided by the WebSocket API out of the box.

This is akin to jQuery's decision of creating a feature-rich and simple $.ajax API as opposed to normalizing XMLHttpRequest.

Fork me on GitHub