Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

WebSockets to Socket.io

DZone's Guide to

WebSockets to Socket.io

· Web Dev Zone
Free Resource

Never build auth again! Okta makes it simple to implement authentication, authorization, MFA and more in minutes. Try the free developer API today! 

In a previous blog post, I showed how you can use Gevent, ZeroMQ, WebSockets, and Flot to create a nice asynchronous server that graphs events in real time to multiple web consumers. Unfortunately, Chrome is just about the only browser that my demo worked in due to some issues with the WebSockets standard. So I've updated the example to use Socket.io, a WebSockets-like Javascript library that will work across multiple browsers.



Prerequisites

The best place to start is my last post; you'll need all the libraries I mentioned there. In addition, you need to install gevent-socketio for Socket.io support in gevent.

Changes from WebSockets server

The first thing we need to change is we need to create a SocketIOServer to replace our WSGIServer with a WebSocketHandler. While we're at it, we'll go ahead and merge our little static file server with the SocketIOServer. Our new main method now looks like this:

def main(): 
    '''Set up zmq context and greenlets for all the servers, then launch the web 
    browser and run the data producer''' 
    context = zmq.Context() 
 
    # zeromq: tcp to inproc gateway 
    gevent.spawn(zmq_server, context) 
    # WSGI server: copies inproc zmq messages to websocket 
    sio_server = SocketIOServer( 
        ('', 8000), SocketIOApp(context), 
        resource="socket.io") 
    # Start the server greenlets 
    sio_server.start() 
    # Open a couple of webbrowsers 
    webbrowser.open('http://localhost:8000/graph.html') 
    webbrowser.open('http://localhost:8000/graph.html') 
    # Kick off the producer 
    zmq_producer(context) 


Now let's take a look at our SocketIOApp:

class SocketIOApp(object): 
    '''Funnel messages coming from an inproc zmq socket to the socket.io''' 
 
    def __init__(self, context): 
        self.context = context 
        self.static_app = paste.urlparser.StaticURLParser( 
            os.path.dirname(__file__)) 
 
    def __call__(self, environ, start_response): 
        if not environ['PATH_INFO'].startswith('/socket.io'): 
            return self.static_app(environ, start_response) 
        socketio = environ['socketio'] 
        sock = self.context.socket(zmq.SUB) 
        sock.setsockopt(zmq.SUBSCRIBE, "") 
        sock.connect('inproc://queue') 
        while True: 
            msg = sock.recv() 
            socketio.send(msg) 


What we've done here is overlay the StaticURLParser provided by paste with our own little ZeroMQ-to-Socket.io gateway. So if a request hits any path starting with /socket.io, it gets routed to our gateway. Otherwise it gets handled as a request for a static resource. We could have had a separate WSGIServer dedicated to handling static requests, but it seemed simpler (to me) to go ahead and combine them here.

Client Updates

Now, for our client, we've made a couple of changes as well. For one, we need to include the socket.io.js library. I've included the one from the socket.io CDN to simplify development:

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


In our javascript, I've also made a few changes to handle the Socket.io protocol better as well as make the graph update a little less choppy. First, we'll set up our socket and some basic variables we'll use later:

$(function() { 
    socket = new io.Socket('localhost'); 
    socket.connect(); 
 
    var $placeholder = $('#placeholder'); 
    var datalen = 100; 
    var plot = null; 
    var series = { 
        label: "Value", 
        lines: { 
            show: true, 
            fill: true 
        }, 
        data: [] 
    }; 


Next, we need to handle the protocol events from socket.io to update our status:

socket.on('connect', function() { 
        $('#conn_status').html('<b>Connected: ' + socket.transport.type + '</b>'); 
    }); 
    socket.on('error', function() { 
        $('#conn_status').html('<b>Error</b>'); 
    }); 
    socket.on('disconnect', function() { 
        $('#conn_status').html('<b>Closed</b>'); 
    }); 


Finally, we will handle the actual messages coming from the server:

socket.on('message', function(msg) { 
        var d = $.parseJSON(msg); 
        series.data.push([d.x, d.y]); 
        while (series.data.length > datalen) { 
            series.data.shift(); 
        } 
        if(plot == null && series.data.length > 10) { 
            plot = $.plot($placeholder, [series], { 
                xaxis:{ 
                    mode: "time", 
                    timeformat: "%H:%M:%S" 
                }, 
                yaxis: { min: 0, max: 5 }, 
                hooks: { 
                    draw: function(plot, canvascontext) { 
                        // Redraw the graph in 50ms 
                        setTimeout(function() { 
                            plot.setData([series]); 
                            plot.setupGrid(); 
                            plot.draw();}, 50); 
                    } 
                } 
            }); 
        } 
    }); 
}); 


What we're doing here is pushing the value from the server on an array, shifting off the old values. Then we set up a hook for Flot to redraw the graph every 50ms when drawing completes. Altogether, there aren't too many changes from our WebSockets demo, and that demo itself wasn't too complex. If you'd like to see all the code, you can at my SourceForge Repo. Hope you've enjoed these posts as much as I've enjoyed playing around with these libraries. Happy hacking!

 

Source: http://blog.pythonisito.com/2011/08/websockets-to-socketio.html


Launch your application faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}