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

infinite loop cannot be connected websocket server

客户端连接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)

您的无限循环必须通过执行 yieldawait 或从 tail_log 函数返回,将控制权交还给 Tornado 的事件循环。由于您的无限循环不会将控制权交给事件循环,因此事件循环永远无法处理更多事件,包括新的 websocket 连接。

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

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,请将 "async def" 替换为 @gen.coroutine,将 "await" 替换为 "yield",然后将 "break" 对于 "return".