子进程 popen.communicate() 与 stdin.write() 和 stdout.read() [英] subprocess popen.communicate() vs. stdin.write() and stdout.read()

查看:111
本文介绍了子进程 popen.communicate() 与 stdin.write() 和 stdout.read()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到两种不同的行为和两种方法应该会产生相同的结果.

I have noticed two different behaviors with two approaches that should have result in the same outcome.

目标 - 使用 subprocess 模块执行外部程序,发送一些数据并读取结果.

The goal - to execute an external program using subprocess module, send some data and read the results.

外部程序为PLINK,平台为WindowsXP,Python 3.3版.

The external program is PLINK, platform is WindowsXP, Python version 3.3.

主要思想-

execution=["C:\\Pr..\\...\\plink.exe", "-l", username, "-pw", "***", IP]
a=subprocess.Popen(execution, bufsize=0, stdout=PIPE, stdin=PIPE, stderr=STDOUT, shell=False)
con=a.stdout.readline()
if (con.decode("utf-8").count("FATAL ERROR: Network error: Connection timed out")==0):
   a.stdin.write(b"con rout 1\n")
   print(a.stdout.readline().decode("utf-8"))
   a.stdin.write(b"infodf\n")
   print(a.stdout.readline().decode("utf-8"))
else:
   print("ERROR")
a.kill()

到目前为止一切顺利.

现在,我希望能够做一个循环(在每次写入子进程的标准输入之后),等待直到子进程标准输出的 EOF,打印它,然后是另一个标准输入命令,等等.

Now, I want to be able to do a loop (after each write to the sub process's stdin), that waits untill EOF of the sub process's stdout, print it, then another stdin command, and so on.

所以我首先尝试了之前关于同一主题收益的讨论(来自子进程命令的实时输出, 逐行读取子进程标准输出, python,子进程:从子进程读取输出) .

So I first tried what previous discussions about the same topic yield (live output from subprocess command, read subprocess stdout line by line, python, subprocess: reading output from subprocess) .

并且它没有工作(它永远挂起)因为 PLINK 进程一直保持活动状态直到我自己杀死它,所以等待子进程的 stdout 到达 EOF 或在 stdout 时执行循环是没有用的真的,因为它永远是真的,直到我杀死它.

And it didnt work (it hangs forever) because the PLINK process is remaining alive untill I kill it myself, so there is no use of waiting for the stdout of the sub process to reach EOF or to do a loop while stdout is true because it will always be true until I kill it.

所以我决定每次写入标准输入时从标准输出读取两次(对我来说已经足够了)-

So I decided to read from stdout twice every time I am writing to stdin (good enought for me)-

execution=["C:\\Pr..\\...\\plink.exe", "-l", username, "-pw", "***", IP]
a=subprocess.Popen(execution, bufsize=0, stdout=PIPE, stdin=PIPE, stderr=STDOUT, shell=False)
con=a.stdout.readline()
if (con.decode("utf-8").count("FATAL ERROR: Network error: Connection timed out")==0):
   a.stdin.write(b"con rout 1\n")
   print(a.stdout.readline().decode("utf-8"))
   print(a.stdout.readline().decode("utf-8"))   //the extra line [1]
   a.stdin.write(b"infodf\n")
   print(a.stdout.readline().decode("utf-8"))
   print(a.stdout.readline().decode("utf-8"))   //the extra line [2]
else:
   print("ERROR")
a.kill()

但第一个额外的 readline() 永远挂起,据我所知,原因与我提到的相同.第一个额外的 readline() 永远等待输出,因为唯一的输出已经在第一个 readline() 中读取,并且因为 PLINK 是活动的,函数只是坐下"" 在那里等待一个新的输出行.

But the first extra readline() hangs forever, as far as I understand, for the same reason I mentioned. The first extra readline() waits forever for output, because the only output was already read in the first readline(), and because PLINK is alive, the function just "sit" there and waits for a new output line to get.

所以我尝试了这段代码,期待同样的挂起,因为在我杀死它之前 PLINK 永远不会死-

So I tried this code, expecting the same hang because PLINK never dies until i kill it-

execution=["C:\\Pr..\\...\\plink.exe", "-l", username, "-pw", "***", IP]
a=subprocess.Popen(execution, bufsize=0, stdout=PIPE, stdin=PIPE, stderr=STDOUT, shell=False)
con=a.stdout.readline()
if (con.decode("utf-8").count("FATAL ERROR: Network error: Connection timed out")==0):
   a.stdin.write(b"con rout 1\n")
   print(a.stdout.readline().decode("utf-8"))
   a.stdin.write(b"infodf\n")
   print(a.stdout.readline().decode("utf-8"))
   print(a.communicate()[0].decode("utf-8"))     //Popen.communicate() function
else:
   print("ERROR")
a.kill()

我试过了,因为根据communicate()的文档,函数会等到进程结束,然后它就结束了.此外,它从标准输出读取直到 EOF.(与读写标准输出和标准输入相同)

I tried that because according to the documentation of communicate(), the function wait until the process is ended, and then it finishes. Also, it reads from stdout until EOF. (same as writing and reading stdout and stdin)

但是 communicate() 完成并且没有挂起,与前面的代码块相反.

But communicate() finishes and does not hang, in opposite of the previous code block.

我在这里错过了什么?为什么使用 communicate() 时 PLINK 会结束,而使用 readline() 时却没有?

What am I missing here? why when using communicate() the PLINK ends, but when using readline() it does not?

推荐答案

你的程序没有 communicate() 死锁,因为两个进程都在等待对方写一些东西,然后他们自己再写一些东西.

Your program without communicate() deadlocks because both processes are waiting on each other to write something before they write anything more themselves.

communicate() 在您的示例中不会死锁,因为它会关闭流,就像命令 a.stdin.close() 一样.这会向您的子进程发送一个 EOF,让它知道没有更多的输入,因此它可以关闭自己,从而关闭其输出,因此 a.stdout.read() 最终返回一个EOF(空字符串).

communicate() does not deadlock in your example because it closes the stream, like the command a.stdin.close() would. This sends an EOF to your subprocess, letting it know that there is no more input coming, so it can close itself, which in turn closes its output, so a.stdout.read() eventually returns an EOF (empty string).

没有特殊信号表明您的主进程将从您的子进程接收到让您知道它已完成从一个命令写入结果,但已准备好接收另一个命令.

There is no special signal that your main process will receive from your subprocess to let you know that it is done writing the results from one command, but is ready for another command.

这意味着要像您尝试的那样与一个子进程来回通信,您必须读取子进程发送的确切行数.就像您看到的,如果您尝试读取太多的线,你僵局.您或许能够使用您所知道的(例如您发送的命令以及您目前看到的输出)来确定要读取的确切行数.

This means that to communicate back and forth with one subprocess like you're trying to, you must read the exact number of lines that the subprocess sends. Like you saw, if you try to read too many lines, you deadlock. You might be able to use what you know, such as the command you sent it, and the output you have seen so far, to figure out exactly how many lines to read.

这篇关于子进程 popen.communicate() 与 stdin.write() 和 stdout.read()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆