python - Multiple tornado clients simultaneously connecting to tornado server
Asked Answered
S

2

-1

I have my Tornado client continuously listening to my Tornado server in a loop, as it is mentioned here - http://tornadoweb.org/en/stable/websocket.html#client-side-support. It looks like this:

import tornado.websocket
from tornado import gen

@gen.coroutine
def test():
    client = yield tornado.websocket.websocket_connect("ws://localhost:9999/ws")
    client.write_message("Hello")

    while True:
        msg = yield client.read_message()
        if msg is None:
            break
        print msg

    client.close()

if __name__ == "__main__":
    tornado.ioloop.IOLoop.instance().run_sync(test)

I'm not able to get multiple instances of clients to connect to the server. The second client always waits for the first client process to end before it connects to the server. The server is set up as follows, with reference from Websockets with Tornado: Get access from the "outside" to send messages to clients and Tornado - Listen to multiple clients simultaneously over websockets.

class WSHandler(tornado.websocket.WebSocketHandler):

    clients = set()

    def open(self):
        print 'new connection'
        WSHandler.clients.add(self)

    def on_message(self, message):
         print 'message received %s' % message
         # process received message
         # pass it to a thread which updates a variable
         while True:
             output = updated_variable
             self.write_message(output)

    def on_close(self):
        print 'connection closed'
        WSHandler.clients.remove(self)

application = tornado.web.Application([(r'/ws', WSHandler),])

if __name__ == "__main__":
     http_server = tornado.httpserver.HTTPServer(application)
     http_server.listen(9999)
     tornado.ioloop.IOLoop.instance().start()

But this has not worked - for some reason even after I have made a successful first connection, the second connection just fails to connect i.e. it does not even get added to the clients set.

I initially thought the while True would not block the server from receiving and handling more clients, but it does as without it multiple clients are able to connect. How can I send back continuously updated information from my internal thread without using the while True?

Any help would be greatly appreciated!

Sixgun answered 1/8, 2018 at 14:11 Comment(0)
S
-1

Thanks for your answer @xyres! I was able to get it to work by starting a thread in the on_message method that handed processing and the while True to a function outside the WSHandler class. I believe this allowed for the method to run outside of Tornado's IOLoop, unblocking new connections.

This is how my server looks now:

def on_message(self, message):
    print 'message received %s' % message
    sendThread = threading.Thread(target=send, args=(self, message))
    sendThread.start()

def send(client, msg):
    # process received msg
    # pass it to a thread which updates a variable
    while True:
        output = updated_variable
        client.write_message(output)

Where send is a function defined outside the class which does the required computation for me and writes back to client inside thewhile True.

Sixgun answered 2/8, 2018 at 13:51 Comment(0)
K
1

To write messages to client in a while loop, you can use the yield None inside the loop. This will pause the while loop and then Tornado's IOLoop will be free to accept new connections.

Here's an example:

@gen.coroutine
def on_message(self):
    while True:
        self.write_message("Hello")
        yield None
Knowledgeable answered 2/8, 2018 at 3:2 Comment(0)
S
-1

Thanks for your answer @xyres! I was able to get it to work by starting a thread in the on_message method that handed processing and the while True to a function outside the WSHandler class. I believe this allowed for the method to run outside of Tornado's IOLoop, unblocking new connections.

This is how my server looks now:

def on_message(self, message):
    print 'message received %s' % message
    sendThread = threading.Thread(target=send, args=(self, message))
    sendThread.start()

def send(client, msg):
    # process received msg
    # pass it to a thread which updates a variable
    while True:
        output = updated_variable
        client.write_message(output)

Where send is a function defined outside the class which does the required computation for me and writes back to client inside thewhile True.

Sixgun answered 2/8, 2018 at 13:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.