Python Can';t关闭使用Popen打开的SSH连接
我创建了一个类方法(仅在Linux上运行),它通过SSH向远程计算机发送命令列表,并使用subprocess.Popen返回输出:Python Can';t关闭使用Popen打开的SSH连接,python,python-3.x,ssh,Python,Python 3.x,Ssh,我创建了一个类方法(仅在Linux上运行),它通过SSH向远程计算机发送命令列表,并使用subprocess.Popen返回输出: def remoteConnection(self, list_of_remote_commands): ssh = subprocess.Popen(["ssh", self.ssh_connection_string], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PI
def remoteConnection(self, list_of_remote_commands):
ssh = subprocess.Popen(["ssh", self.ssh_connection_string], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True, bufsize=0)
# send ssh commands to stdin
for command in list_of_remote_commands:
ssh.stdin.write(command + "\n")
ssh.stdin.close()
output_dict = {'stdin': list(ssh.stdin), 'stdout': list(ssh.stdout), 'stderr': list(ssh.stderr)}
return output_dict
虽然我还在学习子流程模块,但我读了很多关于Popen的书,没有人提到过关闭它(,),所以我认为这不是问题
然而,当在ipython中测试函数外部时,我注意到变量ssh
似乎仍然处于活动状态。我试图关闭ssh.stdin、ssh.stdout和ssh.stderr,甚至是ssh.close()、ssh.terminate()和ssh.kill(),但似乎没有任何东西可以关闭它。我想也许这无关紧要,但我的函数会在几个月甚至几年内被多次调用,所以我不希望每次运行它时都产生一个新的进程,否则我会很快耗尽我的最大进程限制。因此,我使用ssh.pid来查找pid,并使用ps aux | grep pid
进行查找,即使完成了上述所有操作,它仍然存在
我还尝试:
with subprocess.Popen(["ssh", self.ssh_connection_string], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True, bufsize=0) as shh:
而不是:
ssh = subprocess.Popen(["ssh", self.ssh_connection_string], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True, bufsize=0)
我还记得不久前使用ssh-T
解决了一个类似的问题,但甚至:
ssh = subprocess.Popen(["ssh", "-T", self.ssh_connection_string], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True, bufsize=0)
没用
我相信如果我需要的话,我会找到一些关于关闭Popen的信息,但是为什么这个过程仍然在我的计算机上打开?有人能帮我了解这里发生了什么吗?在您的情况下,您在这里遇到了死锁:
output_dict = {'stdin': list(ssh.stdin), 'stdout': list(ssh.stdout), 'stderr': list(ssh.stderr)}
主要是因为list(ssh.stdin)
永远阻塞:尝试读取进程的标准输入不起作用(还有一个额外的风险,因为您将标准输出和错误重定向到不同的管道,而不使用线程来使用它们)
您的意思是使用ssh.communicate
,将整个输入作为参数传递。简单地做:
command_input = "".join(["{}\n".format(x) for x in list_of_remote_commands])
output,error = ssh.communicate(command_input) # may need .encode() for python 3
return_code = ssh.wait()
然后
我可以补充一点,在特定的ssh情况下,使用paramiko模块更好()并且避免完全使用
子流程。ssh.communicate
命令抛出错误:AttributeError:'list'对象没有属性'encode'
也许您的意思是:command\u input=“\n”。join(远程命令列表)+“\n”
?打开与popen
的ssh
连接听起来是一种不好的做法,您是否研究过ssh
或paramiko
?
output_dict = {'stdin': list_of_commands, 'stdout': output.splitlines(), 'stderr': error.splitlines()}