我如何使用 Python Tornado 通过 HTTP 实现“tail”?

2024-04-04

我正在尝试使用 Python 通过 HTTP 实现类似“tail -f”的东西。目前,我正在尝试使用 Tornado,但它一次只能处理一个连接,即使我执行异步请求也是如此。

import socket
import subprocess

import tornado.gen as gen
import tornado.httpserver
import tornado.ioloop
import tornado.iostream
import tornado.options
import tornado.web

from tornado.options import define, options

define("port", default=8888, help="run on the given port", type=int)
define(
    "inputfile",
    default="test.txt",
    help="the path to the file which we will 'tail'",
    type=str)


class MainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    @gen.engine
    def get(self):
        print "GOT REQUEST"
        inputfile = open(options.inputfile)
        p = subprocess.Popen(
            "./nettail.py",
            stdin=inputfile,
            stdout=subprocess.PIPE)
        port_number = int(p.stdout.readline().strip())

        self.write("<pre>")
        self.write("Hello, world\n")
        self.flush()

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
        stream = tornado.iostream.IOStream(s)
        yield gen.Task(stream.connect, ("127.0.0.1", port_number))
        while True:
            data = yield gen.Task(stream.read_until, "\n")
            self.write(data)
            self.flush()

def main():
    tornado.options.parse_command_line()
    application = tornado.web.Application([
        (r"/", MainHandler),
    ])
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()

我正在启动的过程是一个简单的“尾部”,它输出到套接字。

import random
import socket
import sys
import time

#create an INET, STREAMing socket
s = socket.socket(
    socket.AF_INET, socket.SOCK_STREAM)

# Open the connection.
try:
    for attempt_number in xrange(5):
        port_number = random.randint(9000, 65000)
        try:
            s.bind(("localhost", port_number))
        except socket.error:
            continue
        # We successfully bound!
        sys.stdout.write("{0}".format(port_number))
        sys.stdout.write("\n")
        sys.stdout.flush()
        break

    #become a server socket
    s.listen(5)

    # Accept a connection.
    try:
        (clientsocket, address) = s.accept()

        while True:
            line = sys.stdin.readline()
            if not line:
                time.sleep(1)
                continue
            clientsocket.sendall(line)
    finally:
        clientsocket.close()

finally:
    s.close()

./nettail.py 按我的预期工作,但 Tornado HTTP 服务器一次只处理一个请求。

我想使用长时间运行的持久 HTTP 连接来执行此操作,因为它与旧版浏览器兼容。据我所知,Web Sockets 是现代浏览器中的实现方式。

编辑: 我在 Linux 和 Solaris 上运行它,而不是在 Windows 上。这意味着我could在文件上使用tornado.iostream,而不是通过套接字程序。不过,这不是一个记录在案的功能,因此我为每个连接启动一个套接字程序。


经过更多调试后,发现该尾部服务器毕竟没有阻塞。

我试图在打开两个 Firefox 窗口的情况下测试并发连接,但 Firefox 在手动停止第一个窗口之前不会开始获取第二个窗口。我猜 Firefox 不喜欢有两个并发的 HTTP 连接来获取相同的资源。

打开 Firefox 窗口和 Chromium 窗口,我可以看到“尾部”输出推送到两个选项卡。

谢谢你的帮助。 @abarnert 的评论特别有帮助。

Edit:

在即将发布的 Tornado 2.4.2 版本中,“管道”IOStream 已实现 https://tornado.readthedocs.org/en/latest/iostream.html#tornado.iostream.PipeIOStream。使用这个和常规的“尾部”可以大大简化代码。

import subprocess

import tornado.httpserver
import tornado.ioloop
import tornado.iostream
import tornado.options
import tornado.web

from tornado.options import define, options

define("port", default=8888, help="run on the given port", type=int)
define(
    "inputfile",
    default="test.txt",
    help="the path to the file which we will 'tail'",
    type=str)


class MainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        print "GOT REQUEST"
        self.p = subprocess.Popen(
            ["tail", "-f", options.inputfile, "-n+1"],
            stdout=subprocess.PIPE)

        self.write("<pre>")
        self.write("Hello, world\n")
        self.flush()

        self.stream = tornado.iostream.PipeIOStream(self.p.stdout.fileno())
        self.stream.read_until("\n", self.line_from_nettail)

    def on_connection_close(self, *args, **kwargs):
        """Clean up the nettail process when the connection is closed.
        """
        print "CONNECTION CLOSED!!!!"
        self.p.terminate()
        tornado.web.RequestHandler.on_connection_close(self, *args, **kwargs)

    def line_from_nettail(self, data):
        self.write(data)
        self.flush()
        self.stream.read_until("\n", self.line_from_nettail)

def main():
    tornado.options.parse_command_line()
    application = tornado.web.Application([
        (r"/", MainHandler),
    ])
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我如何使用 Python Tornado 通过 HTTP 实现“tail”? 的相关文章

随机推荐

  • 具有 2FA 的 Asp.Net Identity - 记住会话后不保留浏览器 cookie

    我正在使用带有 Asp Identity 和两因素身份验证的 MVC5 2 的最新示例代码 启用 2FA 后 当用户登录时 系统会提示输入代码 通过电话或电子邮件发送 并且他们可以选择 记住浏览器 这样他们就不会在该浏览器上再次要求输入代码
  • 在flex中以编程方式获取SIM号码

    我想以编程方式获取SIM号码 在flex中可以吗 在android开发人员指南中我看到了电话管理器类 同样我们在flex中有什么东西吗 提前致谢 看看这个 这确实是一个 hack 但却是您从 Flex Mobile 调用 Java API
  • 使用不带操作栏的选项菜单

    我正在使用它来隐藏 Android 应用程序中的操作 标题栏 this requestWindowFeature Window FEATURE NO TITLE 我用这个创建了我的选项菜单 MenuInflater inflater get
  • Android 每 4 秒运行一个任务

    您好 我需要每 4 秒调用一个方法 即使设备处于睡眠状态 我使用带有服务 Start stick 的警报管理器 服务名称为 TransactionService 当设备处于活动状态并且每 4 秒调用一次该方法时 代码运行良好 但是当屏幕锁定
  • Django+MongoDB 与 Node.js+MongoDB

    我已经建立并运行了一个带有使用 Python Django MySQL 构建的同步服务的网站 很长一段时间以来 我一直在关注 Node js 和 MongoDB 方面 我即将做出决定 将系统的一部分迁移到 MongoDB 该系统托管来自用户
  • 在回发期间保留 C# 对象

    我有一个 asp net 页面 其中包含 C 代码隐藏 它在 Page Load 方法中执行一些操作 例如查询数据库并进行一些其他调用以使用数据填充对象 然后我在页面上显示这些数据 这一切都很好 我设置了几个回发 以便当单击列表框中的值时
  • R中按字符串列名聚合

    我想按两列对 data frame 中的数据进行分组 然后对特定的第三列进行求和 例如 gt aggregate mpg gear cyl data mtcars FUN sum gear cyl mpg 1 3 4 21 5 2 4 4
  • GUI 开发人员如何处理可变像素密度?

    当今的显示器在尺寸和分辨率方面具有相当大的范围 例如 我的 34 5 厘米 19 5 厘米显示屏 对角线为 39 6 厘米或 15 6 英寸 具有 1366 768 像素 而对角线为 15 英寸的 MacBook Pro 第三代 具有 28
  • 使用 dplyr 将组汇总为区间

    H 我有一个像这样的数据框 d lt data frame v1 seq 0 9 9 0 1 v2 rnorm 100 v3 rnorm 100 gt head d v1 v2 v3 1 0 0 0 01431916 0 5005415 2
  • 如何使用 JodaTime 获取一年中的天数?

    我已尝试以下方法但无济于事 new Period Years ONE getDays new Period 1 0 0 000 getDays 我想要的答案显然是365 你想要的答案并不明显365 它是365 or 366 您在示例中没有考
  • Rancher - 如何公开我的服务?

    我有一个正在运行的 Rancher 设置 如下所示 主机 运行牧场主 https github com rancher rancher容器 在公共IP上 无法从 Internet 访问专用网络 10 1 1 0 24 中的节点 我的目标是使
  • bootstrap-vue 选择带有过滤器选项的组件?

    在带有 bootstrap vue 的 vue 项目中 我搜索选择组件的工作原理https bootstrap vue js org docs components form select https bootstrap vue js or
  • 在同一个“分配”对象上多次调用初始化程序是否安全?

    我可以构建一个UIImageView对象与myImageView UIImageView alloc initWithImage image 如果我想更改 UIImageView 上的图像 则影响显示的应用程序活动如下 我可以通过重新分配它
  • 现代 x86 成本模型

    我正在编写一个带有 x86 后端的 JIT 编译器 并一边学习 x86 汇编程序和机器代码 我大约 20 年前使用过 ARM 汇编器 对这些架构之间成本模型的差异感到惊讶 具体来说 内存访问和分支在 ARM 上的成本很高 但等效的堆栈操作和
  • 当模态弹出窗口打开时,防止移动“后退按钮”退出网站,而是关闭弹出窗口

    当模式弹出对话框打开时 即使我添加关闭按钮 通常是右上角的 X 移动设备上的一些用户也会使用移动设备的 后退按钮 来关闭弹出窗口 但这将退出该网站 如何让手机 后退按钮 关闭弹窗而不是退出网站 document getElementById
  • Firebase - 更改我的项目的国家/地区

    我在 firebase 中创建项目时错误地选择了错误的国家 地区 正如你在这里看到的 这可以解决吗 我知道项目 ID 无法更改 而且我喜欢我选择的 ID As 文档说 https firebase google com support gu
  • Apollo 3 分页与字段策略

    有人可以提供使用 Apollo Client 3 0 字段策略实现分页的示例吗 我一直在遵循文档中的示例来实现无限滚动 但在我的控制台中我收到以下警告 The updateQuery callback for fetchMore is de
  • 有没有比输入 | 更快的方法来计算 powershell 中的行数?测量对象[重复]

    这个问题在这里已经有答案了 我使用的是 macbook m1 当我使用本机时wc l file我闪电般地得到结果 几乎可以肯定是因为我可以直接传递文件 但是 我不知道如何使用 powershell 执行此操作 并且我被迫将数据汇集到stdo
  • UISwipeGestureRecognizer 被调用两次

    我正在实施的视图遇到问题 这是一个在 CATiledLayer 中显示 pdf 页面的视图 该平铺视图位于 UISCrollView 内部 我让视图控制自身作为 ZoomingPDFView 苹果示例 我做了一些修改 以便在未启用滚动时识别
  • 我如何使用 Python Tornado 通过 HTTP 实现“tail”?

    我正在尝试使用 Python 通过 HTTP 实现类似 tail f 的东西 目前 我正在尝试使用 Tornado 但它一次只能处理一个连接 即使我执行异步请求也是如此 import socket import subprocess imp