Search code examples
pythonwebsockettornado

Tornado websocket model


I'm not very experienced with Python and new to Tornado websockets, so I have a problem grasping the idea how it actually works.

Concretely, this is a usual example:

class EchoWebSocket(tornado.websocket.WebSocketHandler):
    def open(self):
        print("WebSocket opened")

    def on_message(self, message):
        self.write_message(u"You said: " + message)

    def on_close(self):
        print("WebSocket closed")

What confuses me is the way the requests are served. I read that Tornado is non-blocking and if understood well single-threaded, where each request is handled by a handler in a fast way and if the operation lasts longer then there are callbacks which are called when certain operation (e.g. database) is finished. This allows a large number of users to be served. But what confuses me with these websockets and examples, is what is self in this case?

I know that it is a similar thing like this in Java and C#, but I don't understand how this self represents different clients each time a client sends a message? Moreover, is there only a single instance of EchoWebSocket per application, or there is an instance per request?

Additionally, how should I keep the references to the clients? I tried two ways:

class EchoWebSocket(tornado.websocket.WebSocketHandler):

    clients = []

    def open(self):
        print("WebSocket opened")

    def on_message(self, message):
        EchoWebSocket.clients.append(self)
        self.write_message(u"You said: " + message)

    def on_close(self):
        print("WebSocket closed")

And

class EchoWebSocket(tornado.websocket.WebSocketHandler):

    def __init__(self, application, request):
        super(EchoWebSocket,self).__init__(application, request)
        self.clients = []

    def open(self):
        print("WebSocket opened")

    def on_message(self, message):
        self.clients.append(self)
        self.write_message(u"You said: " + message)


    def on_close(self):
        print("WebSocket closed")

But the second approach doesn't seem to be working. What is the proper way to do it and why?


Solution

  • In python, by convention self is a reference to the current class' instance object.

    AFAIK, the tornado framework creates an instance of the class WebSocketHandler for each client. So you don't really have to keep a reference to clients. Each client is naturally handled by a different instance of the handler. Practically it means that self will be different objects for two distinct clients.

    To keep references to connected clients, something like that would work:

    class EchoWebSocket(tornado.websocket.WebSocketHandler):
        all_clients = set()
    
        def open(self):
            self.all_clients.add(self)
    
        def on_message(self, message):
            pass
    
        def on_close(self):
            self.all_clients.remove(self)