I have a server running a loop that reads data from a device and I want to send them to all clients who connect on a websocket on tornado. I tried putting the loop inside the open function but then it can't handle on_close function or new connections.
What is best practice to do that?
#!/usr/bin/env python
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import socket
class MyWebSocketServer(tornado.websocket.WebSocketHandler):
def open(self):
print('new connection'+self.request.remote_ip)
try:
while True:
'''
read and send data
'''
except Exception,error:
print "Error on Main: "+str(error)
def on_close(self):
print('connection closed'+self.request.remote_ip)
application=tornado.web.Application([(r'/ws',MyWebSocketServer),])
if __name__=="__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8000)
print('start')
tornado.ioloop.IOLoop.instance().start()
Thanks
Here's a full example about running your blocking code in a separate thread and broadcasting messages to all connected clients.
...
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=1) # spawn only 1 thread
class MyWebSocketServer(tornado.websocket.WebSocketHandler):
connections = set() # create a set to hold connections
def open(self):
# put the new connection in connections set
self.connections.add(self)
def on_close(self):
print('connection closed'+self.request.remote_ip)
print('new connection'+self.request.remote_ip)
# remove client from connections
self.connections.remove(self)
@classmethod
def send_message(cls, msg):
for client in cls.connections:
client.write_message(msg)
def read_from_serial(loop, msg_callback):
"""This function will read from serial
and will run in aseparate thread
`loop` is the IOLoop instance
`msg_allback` is the function that will be
called when new data is available from usb
"""
while True:
# your code ...
# ...
# when you get new data
# tell the IOLoop to schedule `msg_callback`
# to send the data to all clients
data = "new data"
loop.add_callback(msg_callback, data)
...
if __name__ == '__main__':
loop = tornado.ioloop.IOLoop.current()
msg_callback = MyWebSocketServer.send_message
# run `read_from_serial` in another thread
executor.submit(read_from_serial, loop, msg_callback)
...
loop.start()