When I refresh my client web-page, I stop receiving data from a tornado socket server. How can I reconnect to the stream?
I have tried appending the connection objects to a list and then deleting the connection from the list when it closes but it turns out, when you refresh the page, the connection never closes, it stays active according to the server, but it also does not receive data anymore on the client side:(
This is my tornado server
# python 3
from tornado import web, httpserver, ioloop, websocket, options
from time import time, sleep
class ChannelHandler(websocket.WebSocketHandler):
"""Handler that handles a websocket channel"""
connections = list()
@classmethod
def urls(cls):
return [(r'/websocket', cls, {})]
def initialize(self):
self.channel = None
def open(self):
# When Client opens a websocket
# add the new connnection to connections
self.connections.append(self)
def on_message(self, message):
# Message received on channel
# keep sending all connected clients the time info
while True:
[client.write_message({'time()': str(time())}) for client in self.connections]
sleep(1)
print('still sending')
def on_close(self):
# Channel is closed
# delete client from active connections if they close connection
self.connections.remove(self)
print('CLOSED connection?')
def check_origin(self, origin):
# Override the origin check if needed
return True
def main():
# Create tornado application and supply URL routes
app = web.Application(ChannelHandler.urls())
# Setup HTTP Server
http_server = httpserver.HTTPServer(app)
http_server.listen(8000, 'localhost')
# Start IO/Event loop
ioloop.IOLoop.instance().start()
if __name__ == '__main__':
main()
And the socket client is
<script type="text/javascript">
var ws = new WebSocket("ws://localhost:8000/websocket");
ws.onopen = function () {
ws.send("Hello, world");
};
ws.onmessage = function (evt) {
console.log(evt.data);
};
</script>
So, How can I keep receiving data from a socket server when I refresh my cleint web-page?
The while
loop is blocking your whole server. You've added a sleep(1)
call in the loop to pause the loop for a second, but time.sleep
is a blocking function, hence it's not any help either.
You need to use an asynchronous alternative to time.sleep
—Tornado's gen.sleep
.
You'll also need to convert the on_message
function to a coroutine.
Example:
from tornado import gen
async def on_message(...):
...
while True:
...
await gen.sleep(1)
...
As an additional tip, use a set()
instead of a list()
to store your connections so that you don't accidentally add duplicate connections.
In this case, you'll also need to amend your code a little bit. set
doesn't have an append
method, instead it has an add
method.
connections = set()
...
self.connections.add(self) # to add connection
...
self.connections.remove(self) # to remove connetion