在 Python 中流式传输标准输入/标准输出

Posted

技术标签:

【中文标题】在 Python 中流式传输标准输入/标准输出【英文标题】:Streaming stdin/stdout in Python 【发布时间】:2011-11-18 23:59:01 【问题描述】:

我正在尝试向/从简单的 WebSockets UI 流式传输 bash shell,但我在重定向 IO 时遇到了麻烦。我想启动一个 bash 实例并将 stdout 和 stdin 连接到与我的 Web UI 交互的 write_message() 和 on_message() 函数。这是我正在尝试做的简化版本:

class Handler(WebSocketHandler):
    def open(self):
        print "New connection opened."
        self.app = subprocess.Popen(["/bin/bash", "--norc", "-i"], stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=False)
        thread.start_new_thread(self.io_loop, ())

    def on_message(self, message):
        self.app.stdin.write(message)

    def on_close(self):
        self.app.terminate()

    def io_loop(self):
        while self.app.poll() is None:
            line = self.app.stdout.readline()
            if line:
                self.write_message(line)

虽然 bash 似乎启动并且 on_message 确实被调用,但我没有得到任何输出。 readline() 仍然阻塞。我尝试了 stdout.read()、stdout.read(1) 和各种缓冲区修改,但仍然没有输出。我还尝试在 on_message 中对带有尾随 '\n' 的命令进行硬编码以隔离问题,但我仍然没有从 readline() 获得任何输出。

理想情况下,我希望将写入到标准输出的每个字节实时流式传输,而无需等待 EOL 或任何其他字符,但我很难找到正确的 API。任何指针将不胜感激。

【问题讨论】:

刷新流有帮助吗? 不,我什至尝试用带有 sys.stdout.flush() 的简单 echo 脚本替换 bash。 这个 WebSocketHandler 是什么? @ChrisMorgan 它来自 Tornado。 【参考方案1】:

在我看来就像这条线:

line = self.app.stdout.readline()

将阻止 ioloop 运行,因为应用程序将花费大部分时间挂在 readline() 等待应用程序写入一些输出。为了让它工作,你必须得到进程的stdinstdout(那stderr呢?你也需要捕获它),将它们切换到非阻塞模式,然后将它们添加到ioloop 花费时间循环处理的文件描述符集中。

【讨论】:

您的帖子让我了解了非阻塞 IO 策略,并且我能够使用 asyncproc 来使用它。谢谢! 太棒了!我担心我的回答太简短而无济于事,很高兴它足以让您阅读有关异步的内容,以便您可以解决整个问题。如果您有机会,请编辑您的问题并添加一点“解决方案如下”部分,以便以后遇到此问题的人可以看到完全解决的异步循环是什么样的。

以上是关于在 Python 中流式传输标准输入/标准输出的主要内容,如果未能解决你的问题,请参考以下文章

nodejs/express - 立即将标准输出流式传输到客户端

如何使用 Python 将标准输入/标准输出通过管道传输到 Perl 脚本

将控制台应用程序的标准输出流式传输到 ASP.NET MVC 视图

在 python 中控制 ruby​​ 程序的标准输入和标准输出

Python Popen 在标准输入上发送到进程,在标准输出上接收

如何在 Linux 上使用标准 I/O 函数在多个进程中写入文件?