龙卷风中的推动引擎

vol*_*ile 2 python tornado

我正在尝试在龙卷风中编写一个简单的推送引擎。基本上,我有一个程序在我的服务器上运行,不断生成一个输出,我通过 Python 处理该输出以更新字典,并且我希望将该字典发布到 Web 客户端,例如每分钟发布一次。

如果您的答案包含文档链接或重新表述我自己的问题,我将不胜感激。我正在阅读大量痛苦的龙卷风文档,因此任何帮助将不胜感激。

这是代码的框架,其中有注释解释我想要做什么:

import subprocess
import sys
import pprint

import tornado.ioloop
import tornado.web

# this is to run my bash process and continuously yiled its output
def runProcess(cmd):
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    while True:
        retcode = p.poll()
        line = p.stdout.readline()
        yield line
     if retcode is not None:
         break


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        #What can I do here if I want to send the update data every minute?
        self.write(data)


    def get_data(self):
        data = dict()
        cmd =  'myProg --args' 
        # this program will produce a continuous stream of data
        for line in runProcess(cmd.split()):
            data[line.split()[0] = line.plit()[1]
        #now dictionary is updated? yield result?
        # even if I want to publish updates every minute?
        yield all_data


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

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()
Run Code Online (Sandbox Code Playgroud)

Bor*_*jaX 5

如果您的客户端是网络浏览器,这听起来很适合websockets

下面你会发现一个非常非常简单的例子。您应该添加额外的检查,如连接来源的实际验证、网络套接字关闭时的错误处理(这可能会发生......非常非常频繁)

1) Tornado服务器(文件stack_073.py):

import datetime
import time

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


def get_data():
    return {
        "current_time": datetime.datetime.strftime(
            datetime.datetime.now(), "%Y-%m-%d %H:%M:%S"
        )
    }


class WebSocketHandler(tornado.websocket.WebSocketHandler):
    def check_origin(self, origin):
        return True

    def open(self):
        print("WebSocket opened")
        while True:
            data = get_data()
            self.write_message(data)
            time.sleep(1)


def make_app():
    return tornado.web.Application([
        (r"/websocket", WebSocketHandler),
    ])


if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()
Run Code Online (Sandbox Code Playgroud)

现在,连接到 websocket 并接收推送的 HTML (+Javascript):

2)网络客户端(文件stack_073.html):

<html>
    <header>
        <script type="text/javascript">
            var ws = new WebSocket("ws://localhost:8888/websocket");
            ws.onmessage = function (evt) {
                var current_time_str = JSON.parse(evt.data)['current_time'];
                document.getElementById("date").innerHTML = current_time_str;
            };
        </script>
    </header>

    <body>
        <p id="date"></p>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

如果您在终端上启动 Tornado 服务器,然后打开文件stack_073.html,您应该会看到时间每秒更新一次。正如您所看到的,没有 Javascript 计时器或任何东西(更新来自write_messageTornado 执行的)

这基本上会创建一个从浏览器到服务器的永久挂起的请求,服务器可以使用该请求将数据推送到浏览器:

在此输入图像描述

编辑01(根据OP对此答案的评论):

如果 get_data 是一个应该在第一次连接时调用一次的函数,然后永远运行 [ 。。。] 用yield语句替换return语句可以解决这个问题吗?

差不多,是的。就是在这种情况下,您get_data返回一个生成器,但是是的。看看这两个变化:

def get_data():
    while True:
        yield {
            "current_time": datetime.datetime.strftime(
                datetime.datetime.now(), "%Y-%m-%d %H:%M:%S"
            )
        }
        time.sleep(1)


class WebSocketHandler(tornado.websocket.WebSocketHandler):
    def check_origin(self, origin):
        return True

    def open(self):
        print("WebSocket opened")
        while True:
            data = next(get_data())
            self.write_message(data)
Run Code Online (Sandbox Code Playgroud)

编辑02(根据OP对此答案的评论):

我看不到你的代码中的 html 文件在哪里。当我尝试时,我在浏览器中收到 404 错误

为了使用 Tornado 为您的页面提供服务,您需要一个常规(不是 websocket)处理程序来处理 HTTP 请求以获取“初始”网页。请记住,websocket处理程序仅用于处理 websocket 在 Javascript 中通过打开连接var ws = new WebSocket("ws://localhost:8888/websocket");

然后,上述初始页面几乎会返回我在文件中手动编写的代码stack_073.html,该页面包含 Javascript,随后向 websocket 端点发起另一个/websocket请求 ( ) 例如,您可以在http://中提供 HTML /localhost:8888/script_data通过创建这个非常非常脏的处理程序:

文件stack_073.py

import datetime
import time

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


def get_data():
    while True:
        yield {
            "current_time": datetime.datetime.strftime(
                datetime.datetime.now(), "%Y-%m-%d %H:%M:%S"
            )
        }
        time.sleep(1)


class WebSocketHandler(tornado.websocket.WebSocketHandler):
    def check_origin(self, origin):
        return True

    def open(self):
        print("WebSocket opened")
        while True:
            data = next(get_data())
            self.write_message(data)


class RegularSocketHandler(tornado.web.RequestHandler):
    def get(self):
        self.write(
            "<html>"
            "    <header>"
            "        <script type=\"text/javascript\">"
            "            var ws = new WebSocket(\"ws://%s/websocket\");"
            "            ws.onmessage = function (evt) {"
            "               var current_time_str = JSON.parse(evt.data)['current_time'];"
            "               document.getElementById(\"date\").innerHTML = current_time_str;"
            "            };"
            "        </script>"
            "    </header>"
            "    <body>"
            "        <p id=\"date\"></p>"
            "    </body>"
            "</html>" % (self.request.host))


def make_app():
    return tornado.web.Application([
        (r"/websocket", WebSocketHandler),
        (r"/script_data", RegularSocketHandler)
    ])


if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()
Run Code Online (Sandbox Code Playgroud)