无限循环无法连接websocket服务器

时间:2017-03-22 06:24:39

标签: websocket tornado

客户端连接websocket并调用tail_log方法,新客户端无法连接

如何解决这个问题

def on_message(self, message):

    def tail_log(user,ip,port,cmd,log_path,url):
        cmd = "/usr/bin/ssh -p {port} {user}@{ipaddr} {command} {logpath}" \
            .format(user=user, ipaddr=ip, port=port, command=cmd, logpath=log_path)
        f = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

        while True:
            line = f.stdout.readline().strip()
            if line == '':
                self.write_message('failed')
                break
            self.write_message(line)

    tail_log(user=SSH_USER,ip=IP_ADDR,cmd=CMD,port=SSH_PORT,log_path=LOG_PATH,url=SOCKET_URL)

1 个答案:

答案 0 :(得分:0)

你的无限循环必须通过执行yieldawait或从tail_log函数返回来控制回Tornado的事件循环。由于您的无限循环不会控制事件循环,因此事件循环永远不会处理任何其他事件,包括新的websocket连接。

尝试使用Tornado's own process module异步读取子进程的stdout。像这样:

import tornado.ioloop
import tornado.process
import tornado.web
import tornado.websocket


class TailHandler(tornado.websocket.WebSocketHandler):
    def open(self):
        self.write_message(u"Tailing....")
        self.p = tornado.process.Subprocess(
            "tail -f log.log",
            stdout=tornado.process.Subprocess.STREAM,
            stderr=tornado.process.Subprocess.STREAM,
            shell=True)

        tornado.ioloop.IOLoop.current().add_callback(
            lambda: self.tail(self.p.stdout))

        tornado.ioloop.IOLoop.current().add_callback(
            lambda: self.tail(self.p.stderr))

        self.p.set_exit_callback(self.close)

    async def tail(self, stream):
        try:
            while True:
                line = await stream.read_until(b'\n')
                if line:
                    self.write_message(line.decode('utf-8'))
                else:
                    # "tail" exited.
                    return
        except tornado.iostream.StreamClosedError:
            # Subprocess killed.
            pass
        finally:
            self.close()

    def on_close(self):
        # Client disconnected, kill the subprocess.
        self.p.proc.kill()


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("""<html><head><script>
        var ws = new WebSocket("ws://localhost:8888/tail");
ws.onmessage = function (evt) {
   document.write('<p>' + evt.data + '</p>');
};</script></head></html>""")


def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
        (r"/tail", TailHandler),
    ])


app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()

如果您还没有使用Python 3.5,请将@gen.coroutine替换为“async def”,将“yield”替换为“await”,并将“break”替换为“return”。