Depois de tentar algumas implementações diferentes, descobri que o tornado funcionava.
Aqui está o código reunido a partir de duas fontes:
Servidor:
from tornado import websocket
import tornado.ioloop
class EchoWebSocket(websocket.WebSocketHandler):
def open(self):
print "Websocket Opened"
def on_message(self, message):
self.write_message(u"You said: %s" % message)
def on_close(self):
print "Websocket closed"
application = tornado.web.Application([(r"/", EchoWebSocket),])
if __name__ == "__main__":
application.listen(9000)
tornado.ioloop.IOLoop.instance().start()
Cliente:
$(document).ready(function(){
var socket = new WebSocket('ws://127.0.0.1:9000/');
socket.onopen = function(event){
socket.send('Hi');
}
socket.onmessage = function(event){
console.log(event.data);
};
$(window).unload(function(event){
socket.close();
});
});
Testado no Firefox 15.01 e Chrome 22.0.1229.79.