【问题标题】:python - handle tornado connections into while looppython - 将龙卷风连接处理到while循环中
【发布时间】:2018-05-11 01:41:12
【问题描述】:

我有一个服务器运行一个从设备读取数据的循环,我想将它们发送给在龙卷风上连接到 websocket 的所有客户端。 我尝试将循环放在 open 函数中,但它无法处理 on_close 函数或新连接。

这样做的最佳做法是什么?

#!/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()

谢谢

【问题讨论】:

  • 你不需要while read,而是添加另一个函数on_message。查看官方文档:tornadoweb.org/en/stable/…
  • 我知道 on_message 函数,但是在 while 循环中我从设备读取数据,我需要通过 websocket 发送它们。
  • 你如何在while 循环中读取数据?似乎该代码阻塞了服务器。
  • 在 while 循环中,有一段代码可以从通过 USB 连接到串行 IC 的设备中连续读取数据。我需要 while 循环,因为我需要以大约 50Hz 的速率获取这些数据
  • @Miky 是的,while 循环内的代码阻塞了服务器,当它开始运行时,没有其他东西可以运行。尝试使用 ThreadPoolExecutor 在单独的线程中运行 while 循环。

标签: python loops websocket tornado


【解决方案1】:

这是一个完整的示例,关于在单独的线程中运行阻塞代码并将消息广播到所有连接的客户端。

...

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()

【讨论】:

  • 几个问题:1) 为什么你循环使用connections 而不是使用self.write_message(msg)2)我如何键盘中断线程?
  • @Miky 1) 如果你只是做self.write_message,它只会将消息写入当前客户端。在您的问题中,您说您想将消息发送给所有连接的客户端,这就是我循环访问connections 的原因。 2) 如果你的键盘中断,整个进程将停止 - Tornado 服务器以及线程executor。如果只想停止线程executor,可以捕获KeyboardInterrupt异常并使用executor.shutdown(),它会停止线程。
  • 如果我想添加一个线程,例如定期监控cpu温度?
  • @Miky 所以添加一个线程。我不明白这有什么令人困惑的地方。
  • 所以我只需要设置max_workers=2 并添加executor.submit(monitor_cpu_temperature, loop, msg_callback) 即可运行该函数并能够通过ws 发送数据对吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多