This library is designed to organize a permanent connection between the server and the browser.
The main advantage of the library: it automatically adjusts to the capabilities of the browser and uses the most efficient transport protocol among those supported.
Is the browser able to web sockets? Great, we will use them. Is the browser able to AJAX? We will use long polling. Is it an ancient Internet Explorer? We will use html file object. Well, and so on.
')
About socket.io already
wrote on Habré. The “native” Socket.IO server is written in node.js.
What is TornadIO2?
This is a library running on top of Tornado and supporting the current version of the Socket.IO protocol.
The main advantage of the library is that it provides a convenient abstraction over a virtual connection, so the developer will not have to think about how the transport will work in different conditions.
Why is TornadIO2 called? Because there is TornadIO, which supports older versions of Socket.IO and older versions of Tornado (1.2, for example). Starting with Socket.IO 0.7, the transport protocol changed and a new functionality appeared that did not fit into the architecture of the first TornadIO. In addition, TornadIO2 requires Tornado 2.1 or higher.
The project home page is here:
http://github.com/MrJoes/tornadio2Documentation (in English) is here:
http://tornadio2.readthedocs.org/Closer to the code
The simplest client Socket.IO looks like this:
var conn = io.connect('http://myserver'); conn.on('connect', function() { alert('connected'); }); conn.on('message', function(msg) { alert('Got ' + msg); }); conn.on('disconnect', function() { alert('disconnected'); });
Roughly speaking, we create a connection object, and then add reactions to different events: connection, receiving a message, and disconnecting from the server.
If we want to send a message to the server, we do:
conn.send('Hello World!');
Socket.IO supports sending json objects:
conn.json.send({msg: 'Hello World', a: 10});
Now let's see how the simplest server looks like:
from tornado import web from tornadio2 import SocketConnection, TornadioRouter, SocketServer
In this example, the main part is
MyConnection . When a client joins the server, TornadIO2 will create an instance of this class and call
on_open () . When the server receives a message from the client, it will call
on_message with the message sent. And so on.
TornadioRouter works with one class of connection and implements all the network logic necessary for the proper operation of the socket.io client.
Then we create the Tornado application, feed it links from the router and start the server.
SocketServer is just a convenient wrapper for starting the Tornado HTTP server and
Flash Policy Server to support FlashSocket transport.
You can send both strings and regular objects, the main thing is that they are normally serialized in json.
Developments
In the latest versions of Socket.IO, the concept of events appeared - instead of sending “normal” messages, the function call is emulated and an RPC is obtained. Naturally, if you make a mistake with the number of parameters (or their names), an exception will occur and the connection will simply close.
The event is sent as follows:
var conn = io.connect('http://myserver:1234'); conn.on('connect', function() { conn.emit('hello', 'Joes'); });
And on the server they are processed like this:
from tornadio2 import SocketConnection, event class MyConnection(SocketConnection): @event('hello') def hello(self, name): print 'Got hello from %s' % name
Similarly, sending events from the server and processing them on the client works:
var conn = io.connect('http://myserver:1234'); conn.on('connect', function() { conn.emit('ping', 'Joes'); }); conn.on('pong', function(name) { alert(name); // Will show Joes });
And the server:
from tornadio2 import SocketConnection, event class MyConnection(SocketConnection): @event('ping') def ping(self, name): self.emit('pong', name)
Confirmations
When sending a message or event, you can request a confirmation - when the message is received and processed, an ACK packet will be automatically sent and the transferred callback will be called.
In the case of events, you can return the value from the handler and it will automatically go to the client, thereby obtaining a convenient code for the REQUEST / RESPONSE pattern.
From an API point of view, it all looks like this:
var conn = io.connect('http://localhost'); conn.on('connect', function() { // Emit 'whoareyou' event and provide callback function that will be // called once event was handled by the server. conn.emit('whoareyou', function(name) { alert(name); // Will print 'Joes' }); });
And the server:
class MyConnection(SocketConnection): @event('whoareyou') def woohoo(self): return 'Joes'
The server can also send messages with the need for confirmation. To do this, you must pass a callback for
self.send () or use
self.emit_ack () for events:
class MyConnection(SocketConnection): @event('hello') def myhello(self): self.emit_ack('hello', self.on_ack) def on_ack(self, msg, data): print 'Woohoo, got ACK', msg, data
Starting with Tornado 2.1.0, a convenient interface for writing asynchronous code without callbacks has appeared.
When using
tornado.gen , the code will work asynchronously - if there are two messages from the client and the first start is processed asynchronously, the second will be processed before the first one is finished. This is not always what is expected from the server.
The decorator
tornadio2.gen.sync_engine was created specifically for this purpose.
If you “wrap” the message processor (or events) as a decorator, the messages will be processed in the order they are received, but ioloop will not be blocked.
It is best to see
an example that illustrates how this all works.
Performance monitor
TornadIO2 includes a simple monitor that counts various events: the number of active connections, the number of sent and received messages per second, and so on. The list of counters is not very big yet, so I will be happy with the wishes.
There is a simple
example that shows how to work with data - it builds a graph and shows statistics in real time, which looks something like this:

Performance
Unfortunately, full-fledged load testing of the library has not yet been conducted, so I can’t voice any real figures on performance. If anyone wants to test, I will be very grateful.
The server code is quite lightweight and overhead should not be very noticeable.
Examples
TornadIO2 contains several examples of use: simple chat, ping via socket.io, and so on.
All examples are
here .
Status and Future
TornadIO2 is not yet registered with PyPI - as soon as, so immediately.
The server is ready for use (I hope) - it turns quite well on my small, closed projects. All protocols work, so there should be no special surprises.
I would be grateful for any help in load testing, identifying errors and I hope that someone else will need all this.