我注意到两种方法的两种不同的行为应该导致相同的结果。
目标-使用子过程模块执行外部程序,发送一些数据并读取结果。
外部程序是PLINK,平台是WindowsXP,Python版本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
")
print(a.stdout.readline().decode("utf-8"))
a.stdin.write(b"infodf
")
print(a.stdout.readline().decode("utf-8"))
else:
print("ERROR")
a.kill()
到现在为止还挺好。
现在,我希望能够执行一个循环(每次写入子进程的stdin之后),该循环一直等到子进程的stdout的EOF结束后,打印出来,然后再执行另一个stdin命令,依此类推。
因此,我首先尝试了关于同一主题的先前讨论的内容(子进程命令的实时输出,逐行读取子进程stdout,python,子进程:从子进程读取输出)。
而且它没有用(它永远挂起了),因为PLINK进程一直保持活动状态,直到我自己杀死它为止,因此在stdout为true时无需等待子进程的stdout到达EOF或执行循环,因为在我杀死它之前,它将永远是真的。
所以我决定每次写stdin时都要从stdout读两次(对我来说足够好了)-
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
")
print(a.stdout.readline().decode("utf-8"))
print(a.stdout.readline().decode("utf-8")) //the extra line [1]
a.stdin.write(b"infodf
")
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处于活动状态,因此该函数仅"坐在"那里并等待一条新的输出线。
因此,我尝试了此代码,并期望出现相同的挂起,因为PLINK直到我将其杀死后才会死亡-
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
")
print(a.stdout.readline().decode("utf-8"))
a.stdin.write(b"infodf
")
print(a.stdout.readline().decode("utf-8"))
print(a.communicate()[0].decode("utf-8")) //Popen.communicate() function
else:
print("ERROR")
a.kill()
我尝试了该操作,因为根据communicate()的文档,该功能要等到过程结束后再完成。同样,它从stdout读取直到EOF。 (与写入和读取stdout和stdin相同)
但是communicate()完成并且没有挂起,与上一个代码块相反。
我在这里想念什么?为什么在使用communicate()时PLINK结束,但是在使用readline()时却没有结束?
您的程序没有communicate()死锁,因为这两个进程在互相写东西之前都互相等待着写东西。
在您的示例中,communicate()不会死锁,因为它会像命令a.stdin.close()那样关闭流。这会将EOF发送到您的子进程,让它知道不再有输入,因此可以关闭自身,这又关闭其输出,因此a.stdout.read()最终返回EOF(空字符串)。
您的主进程将不会从子进程收到任何特殊信号,以让您知道它已经完成了从一个命令写入结果的准备,但已准备好用于另一个命令。
这意味着要像您尝试的那样与一个子流程来回通信,必须阅读该子流程发送的确切行数。如您所见,如果您尝试读取过多行??,则会陷入僵局。您也许可以使用您所知道的信息(例如,发送的命令以及到目前为止所看到的输出)来确定要读取的行数。
如果您不想在打开的进程中遇到死锁,请像通常使用键盘Enter( n)发送一样在输入后发送EOF信号。 因此,使用此功能可以避免死锁。 proc.stdin.write(b2 + 2 n),proc.stdin.flush(),print(proc.stdout.readline()。decode())
@ babygame0ver n是行尾,而不是文件尾。 您可以在原始帖子中看到他们已经在发送换行符。 您似乎在想一个特定的过程,该过程总是每行输入响应一行输出。 并非总是如此。
您可以使用线程同时进行读写,尤其是在仅需要将输出打印给用户的情况下:
from threading import Thread
def print_remaining(stream):
for line in stream:
print(line.decode("utf-8"))
con = a.stdout.readline()
if"FATAL ERROR" not in con.decode("utf-8"):
Thread(target=print_remaining, args=[a.stdout]).start()
for cmd in LIST_OF_COMMANDS_TO_SEND:
a.stdin.write(cmd)
我知道我可以用。 请注意我的问题。
事实是,使用subprocess.Popen时,即使在过程终止之前,代码仍会继续读取。尝试将.wait()附加到您的Popen调用中(请参阅文档),
a=subprocess.Popen(execution, bufsize=0, stdout=PIPE, stdin=PIPE, stderr=STDOUT, shell=False).wait()
这将确保执行完成之后再进行其他操作。
抱歉,它不能回答我的问题。 我知道这个事实:)