Tornado Redis websockets chat

Tornado Redis websockets chat 实现的聊天室

This is a simple example of WebSocket + Tornado + Redis Pub/Sub usage.
Do not forget to replace YOURSERVER by the correct value.
Keep in mind that you need the *very latest* version of your web browser.
You also need to add Jacob Kristhammar's websocket implementation to Tornado:
Grab it here:
Or clone my fork of Tornado with websocket included:
Oh and the Pub/Sub protocol is only available in Redis 2.0.0:

Tested with Chrome 6.0.490.1 dev under OS X.

For questions / feedback / coffee -> @kizlum or
Have fun.

Modified by Lorenzo Bolla on 11 Feb 2013:
    Threading done right: don't call Tornado's handlers functions in threads, but use add_callback
    Updated to redis 2.6.9
    Tested with Py3k

from functools import partial
import threading
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import redis
# This is ugly but I did not want to create multiple files for a so trivial
# example.
    <title>Sample test</title>
    <script type="text/javascript" src=""></script>
    # Hello world
    <form method='POST' action='./'>
        <textarea name='data' id="data"></textarea>
        <div><input type='submit'></div>
    <div id="log"></div>
    <script type="text/javascript" charset="utf-8">

                var value = $('#data').val();
                $.post("./", { data: value }, function(data){
                return false;

            if ("WebSocket" in window) {
              var ws = new WebSocket("ws://localhost:8888/realtime/");
              ws.onopen = function() {};
              ws.onmessage = function (evt) {
                  var received_msg =;
                  var html = $("#log").html();
                  html += "<p>"+received_msg+"</p>";
              ws.onclose = function() {};
            } else {
              alert("WebSocket not supported");
def redis_listener():
    r = redis.Redis()
    ps = r.pubsub()
    io_loop = tornado.ioloop.IOLoop.instance()
    for message in ps.listen():
        for element in LISTENERS:
            io_loop.add_callback(partial(element.on_message, message))
class NewMsgHandler(tornado.web.RequestHandler):
    def get(self):
    def post(self):
        data = self.get_argument('data')
        r = redis.Redis()
        r.publish('test_realtime', data)
class RealtimeHandler(tornado.websocket.WebSocketHandler):
    def open(self):
    def on_message(self, message):
    def on_close(self):
settings = {
    'auto_reload': True,
application = tornado.web.Application([
    (r'/', NewMsgHandler),
    (r'/realtime/', RealtimeHandler),
], **settings)
if __name__ == "__main__":
    http_server = tornado.httpserver.HTTPServer(application)
Relative Articles