First hours with node.js and socket.io

Tue 02 July 2013 // posts

At last I spent some time with node.js, socket.io, and more precisely http push technique (comet). My motivation was just to experiment, see how the actual http pushing works (it gets much clearer when using Wireshark and Chrome dev tools) and what it takes to setup the system.

I ended up with node.js + socket.io on the server side, python + socket.io-client on the client side.

As a really brief explanation,

  • node.js is a server side javascript scripting platform (built around google's V8 engine, known for its great performance)...Well, as of now I think of it as a JS interpreter.

  • Socket.io is a library, specially designed for Javascript, leverages http push session handling and delivers a nice event driven messaging system. The actual work is based on this library.

While typical http sessions have one way flow, that is, clients make requests (HTTP GET, POST, etc) in order to get data from the server(poll), http push technique allows clients to get virtually real-time updates from the server.

After figuring out what I just described, it was time for experimenting. Considering that I'm a Python boy, I wanted to bring it into the mix. There are a quite number of possibilities, either run a socket.io server implemented in Python, or use IPC (inter process communication) between node.js and Python (or whatever) apps. I chose IPC, although, when I tried to install one of the most promising solutions - ZeroRPC - I ran into issues (different dependencies versions, etc). I didn't spent much time fixing this, instead, I wondered if one could also use socket.io as a base for IPC....soon to realize that it is possible! EDIT: I've dedicated some time to gevent-socketio. Until now it looks good, well organized and reasonably documented. I'll update the post as soon as I have more details.

Enough with the talking, let's get to the code! But before that, let me conclude what I ended up with:
1. A socket.io server (server.js) running with node.js.
2. A Python app (io-client.py) that connects to socket.io server, receives dummy update requests and returns the dummy results back to the server.
3. A real client (client.html) that also connects to the socket.io server, receives and displays the results, instantly.

Code

server.js

var io = require('socket.io').listen(8080);  
var workerio = require('socket.io').listen(8081);

/*  
Real clients  
*/  
io.sockets.on('connection', function (socket) {

});

/*  
Worker client (python)  
*/  
workerio.sockets.on('connection', function (socket) {  
    socket.on('disconnect', function(message, callback) {  
        io.sockets.emit('worker_disconnected', "worker disconnected");  
    });

    // When we receive an update from worker.  
    socket.on('update_from_worker', function(message, callback) {  
        io.sockets.emit('new_update', message);  
    });

    io.sockets.emit('worker_connected', "worker connected");  
});

function askUpdates()  
{  
    workerio.sockets.emit("please_update", "now");  
    setTimeout(askUpdates, Math.random()*3000);  
};

askUpdates();  

io-client.py

from socketIO_client import SocketIO  
from time import sleep  
from datetime import datetime

socketIO = SocketIO('localhost', 8081)

def pleaseUpdate_cb(*args):  
    socketIO.emit('update_from_worker', "io-client.py: finished update -
    %s" % (datetime.now(),))

socketIO.on("please_update", pleaseUpdate_cb)

while 1:  
    socketIO.wait(seconds=1)  

client.html

<html>
   <head>
      <link href="static/css/style.css" rel="stylesheet">
      <script type="text/javascript"
         src="//www.bitstorm.org/jquery/jquery-1.9.1.min.js"/>  </script>
      <script type="text/javascript"
         src="//www.bitstorm.org/jquery/color-animation/jquery.animate-colors-min.js">  </script>
      <script type="text/javascript"
         src="//127.0.0.1:8080/socket.io/socket.io.js">  </script>
      <script>  
         var socket = io.connect("//127.0.0.1:8080");

         $(window).bind("beforeunload", function() {  
            socket.disconnect();  
         });

         socket.on('new_update', function (msg) {  
             var el = $('#log').prepend($('<p
             class="update">').append($('<em>').text(msg))).css("color",
             "#FF0000");  
             $("#log .update").first().animate({color: '#000000'}, 3500);  
         });

         socket.on('worker_connected', function (msg) {  
             var el =
             $('#log').prepend($('<p>').append($('<b>').text(msg)));  
         });

         socket.on('worker_disconnected', function (msg) {  
             var el =
             $('#log').prepend($('<p>').append($('<b>').text(msg)));  
         });

         $.ready(function () {

         });  
      </script>
      <style type="text/css">  
         #log {  
             display: inline-block;  
             padding: 0 50px;  
             max-height: 300px;  
             overflow-y: scroll;  
         }
         p {  
            margin: 0;  
         }  
      </style>
   </head>
   <body>
      <div id="log">  </div>
   </body>
</html>  

social