与子进程多次通信(多次调用stdout)

时间:2011-05-02 19:22:04

标签: python stream subprocess pipe

在[此主题] [1]上有一个类似的问题。

我想将命令发送到我的子进程,解释响应,然后发送另一个命令。如果必须启动一个新的子进程来实现这一点似乎是一种耻辱,特别是如果subprocess2必须执行许多与subprocess1相同的任务(例如ssh,open mysql)。

我尝试了以下内容:

subprocess1.stdin.write([my commands])
subprocess1.stdin.flush()
subprocess1.stout.read()

但如果没有明确的字节到read()的参数,程序就会执行该指令,我无法为read()提供参数,因为我无法猜出有多少字节可用在溪流中。

我正在运行WinXP,Py2.7.1

修改

感谢@regularfry为我提供了我真实意图的最佳解决方案(阅读他的回复中的评论,因为它们与通过SSH隧道实现我的目标有关)。 (他/她的答案已经被投了票。)然而,为了以后找到标题问题答案的观众的利益,我接受了@Mike Penningtion的回答。

3 个答案:

答案 0 :(得分:2)

您的选择是:

  1. 使用面向行的协议(并使用readline()而不是read()),并确保发送的每个可能的行都是有效的消息;
  2. 使用read(1)和解析器告诉您何时阅读完整的消息;或
  3. 将子消息对象从子进程中解压缩到流中,然后在父进程中取消对它们进行解压缩。这会为您处理邮件长度问题。

答案 1 :(得分:1)

@JellicleCat,我正在跟进评论。我相信wexpect是sage ... AFAIK的一部分,它不是单独打包的,但您可以下载wexpect here

老实说,如果您要开启程序化ssh会话,请使用paramiko。它作为一个独立的安装支持,具有良好的包装,应该在Windows上本地安装。

修改

示例paramiko脚本cd到目录,执行ls并退出...捕获所有结果......

import sys
sys.stderr = open('/dev/null')       # Silence silly warnings from paramiko
import paramiko as pm
sys.stderr = sys.__stderr__
import os

class AllowAllKeys(pm.MissingHostKeyPolicy):
    def missing_host_key(self, client, hostname, key):
        return

HOST = '127.0.0.1'
USER = ''
PASSWORD = ''

client = pm.SSHClient()
client.load_system_host_keys()
client.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
client.set_missing_host_key_policy(AllowAllKeys())
client.connect(HOST, username=USER, password=PASSWORD)

channel = client.invoke_shell()
stdin = channel.makefile('wb')
stdout = channel.makefile('rb')

stdin.write('''
cd tmp
ls
exit
''')
print stdout.read()

stdout.close()
stdin.close()
client.close()

答案 2 :(得分:1)

这种方法可行(我已经这样做了)但需要一些时间并且它使用特定于Unix的调用。您将不得不放弃子进程模块并基于fork / exec和os.pipe()滚动自己的等效项。

使用fcntl.fcntl函数在使用os.pipe()创建子进程的stdin / stdout文件描述符(读取和写入)后,将其放入非阻塞模式(O_NONBLOCK选项常量)。

使用select.select函数轮询或等待文件描述符的可用性。为了避免死锁,您需要使用select()来确保写入不会被阻塞,就像读取一样。即使如此,您还必须在读取和写入时考虑OSError异常,并在收到EAGAIN错误时重试。 (即使在读/写之前使用select,EAGAIN也可以在非阻塞模式下发生;这是一个常见的内核错误,已经证明难以修复。)

如果你愿意在Twisted框架上实现,他们应该为你解决这个问题;您所要做的就是编写一个Process子类。但我自己还没试过。