Reputation: 509
I have a very simple setup inspired by this question: Tornado - Listen to multiple clients simultaneously over websockets
Essentially, I have one Websocket Handler that may connect to many websocket clients. Then I have another websocket handler 'DataHandler' that will broadcast a message everytime it receives a message.
So I made a global list of TestHandler instances and use it to broadcast messages to all the instances
ws_clients = []
class TestHandler(tornado.websocket.WebSocketHandler):
def open(self):
print('open test!')
ws_clients.append(self)
self.random_number = random.randint(0, 101)
def on_message(self, message):
print(message)
print('received', message, self, self.random_number)
self.write_message('Message received')
def on_close(self):
print('closed')
class DataHandler(tornado.websocket.WebSocketHandler):
def open(self):
print('data open!')
def on_message(self, message):
for c in ws_clients:
c.write_message('hello!')
class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/test_service/", TestHandler),
(r"/data/", DataHandler),
(r"/", httpHandler)
]
tornado.web.Application.__init__(self, handlers)
ws_app = Application()
ws_app.listen(8000)
tornado.ioloop.IOLoop.instance().start()
TestHandler can receive messages fine through the address ws://127.0.0.1/test_service/
and DataHandler can receive messages fine through the address ws://127.0.0.1/data/
but whenever I loop through ws_clients
, I never receive any messages on TestHandler
.
Am I doing something wrong?
Upvotes: 1
Views: 623
Reputation: 21744
Here's what I'd do - I'd create a new method on TestHandler
which will serve
one single purpose - take a message and send it to all the connected clients.
Before going into the code, I'd like to point out that it seems (conventionally) better to keep ws_clients
inside the class instead of a global object. And use a set
instead of a list
.
class TestHandler(...):
ws_clients = set() # use set instead of list to avoid duplicate connections
def open(self):
self.ws_clients.add(self)
@classmethod
def broadcast(cls, message):
"""Takes a message and sends to all connected clients"""
for client in cls.ws_clients:
# here you can calculate `var` depending on each client
client.write_message(message)
def on_close(self):
# remove the client from `ws_clients`
self.ws_client.remove(self)
# then you can call TestHandler.broadcast
# from anywhere in your code
# example:
class DataHandler(...):
...
def on_message(self, message):
# pass the message to TestHandler
# to send out to connected clients
TestHandler.broadcast(message)
Upvotes: 3