Marko Marko - 8 days ago 8
Python Question

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?

Answer

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)