Python中的逐行远程数据传输
Posted
技术标签:
【中文标题】Python中的逐行远程数据传输【英文标题】:Line-by-line Remote Data Transmission in Python 【发布时间】:2010-09-27 00:30:07 【问题描述】:我一直在玩 subprocess
模块来迭代发送
输入文件中的每一行到由以下命令创建的进程。
ssh -t -A $host 'remote_command'
remote_command
期望在其 STDIN 中有一行,对
行并迭代循环,直到 STDIN 关闭或到达 EOF。
为了实现这一点,我一直在做的是:
process = subprocess.Popen("ssh -t -A $host 'remote_command'",
shell=True,
stdin=subprocess.PIPE)
for line in file('/tmp/foo'):
process.stdin.write(line)
process.stdin.flush()
process.stdin.close()
但我发现上面的方法不够健壮,因为它是
通常情况下,remote_command
过早完成而不处理
整个内容(尽管有时相同的代码确实可以成功而没有问题)。
当我采用另一种虽然非常相似的方法时,情况也是如此:
process = subprocess.Popen("ssh -t -A $host 'remote_command'",
shell=True,
stdin=file('/tmp/foo'))
所以问题是:如何确保输入文件中的每一行都被 Python 中的远程机器发送、接收和处理直到结束?
【问题讨论】:
【参考方案1】:如果这样……
process = subprocess.Popen("ssh -t -A $host 'remote_command'",
shell=True,
stdin=subprocess.PIPE)
for line in file('/tmp/foo'):
process.stdin.write(line)
process.stdin.flush()
process.stdin.close()
...是你的整个程序,它不会(必然)工作。
虽然对process.stdin.close()
的最终调用会确保在你的程序终止之前所有的数据都已经发送到ssh
进程,但它并不能确保ssh
进程已经通过网络发送了所有的数据,因此很可能有一些未完成的数据要发送。
不幸的是,由于ssh
进程是您程序的子进程,因此当您的程序终止时,ssh
进程将收到一个SIGHUP
,这将立即杀死它,可能在它完成发送所有数据之前.
只要remote_command
在遇到EOF时终止,这不是问题,您可以要求ssh
进程忽略SIGHUP
,并继续在后台运行...
process = subprocess.Popen("nohup ssh -t -A $host 'remote_command'", ...)
...或要求您的程序等待ssh
进程完成,方法是添加...
process.wait()
...到你的程序结束。
更新
经过进一步检查,如果一个进程的控制 tty 终止,而不是它的父进程,它看起来只有一个 SIGHUP
。
这可能与-t
选项有关,该选项在远程主机上创建一个新的控制 tty,并且在它产生的子进程完成之前退出。
在这种情况下,您可能需要...
process = subprocess.Popen("ssh -t -A $host 'nohup remote_command'", ...)
...或者不带-t
选项试试。
【讨论】:
再次感谢我在其他地方从未见过的想法。将尝试nohup
并回复您。
@OTZ 查看更新的答案。可能有助于解释 remote_command
是什么,所以我可以尝试重现问题。【参考方案2】:
除了确保所有输入发送到您的子进程之外,您只能做更多的事情。在我看来,你的第二个例子比第一个好。您可以做的是检查子进程的返回码。
return_code = p.wait()
您的远程命令可能在成功完成时返回 0,如果发生错误,则返回非零值。
【讨论】:
【参考方案3】:与其环绕子进程,不如使用paramiko 之类的东西。
但在任何一种情况下,如果您的连接在您发送所有数据之前终止,您可以捕获该异常并且您会知道您需要重试。如果进程过早终止,您应该能够读取进程的退出代码。
【讨论】:
在这种情况下使用 paramiko 比 subprocess 有什么优势? 使用 paramiko 的优点是您可以更清楚地了解连接失败的原因,因为您会从通信流中获得异常,而不是从 ssh 获得简单的 1 或 0 错误代码二进制通过子进程。【参考方案4】:我会说你最好的选择是使用回复管道来捕获远程命令的结果,并确保你在行之间和每行之后到达一个提示。顺便说一句,我有时发现在远程链接会话结束时使用 ls -l 等虚拟命令有助于确保在断开连接之前完成处理。
【讨论】:
以上是关于Python中的逐行远程数据传输的主要内容,如果未能解决你的问题,请参考以下文章