Paramiko通道在读取大输出时卡住

10 投票
6 回答
28473 浏览
提问于 2025-04-17 14:25

我有一段代码,它可以在远程的Linux机器上执行命令,并使用Paramiko读取输出。代码大概是这样的:

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(IPAddress, username=user['username'], password=user['password'])


chan = self.ssh.get_transport().open_session()

chan.settimeout(10800)

try:
    # Execute thecommand
    chan.exec_command(cmd)

    contents = StringIO.StringIO()

    data = chan.recv(1024)

    # Capturing data from chan buffer.
    while data:
        contents.write(data)
        data = chan.recv(1024)

except socket.timeout:
    raise socket.timeout


output = contents.getvalue()

return output,chan.recv_stderr(600),chan.recv_exit_status()

这段代码在处理小的输出时运行得很好,但当输出变大时,它就会卡住。

这里面是不是有什么和缓冲区有关的问题呢?

6 个回答

2

其实我觉得上面所有的回答都没能解决真正的问题:

如果远程程序首先产生大量的错误输出(stderr),那么

stdout.readlines()
stderr.readlines()

就会一直卡在那里。虽然

stderr.readlines()
stdout.readlines()

可以解决这种情况,但如果远程程序首先产生大量的正常输出(stdout),那就会失败。

我还没有找到解决办法……

9

我在这里分享最终的代码,这段代码是根据布鲁斯·韦恩(:))的输入写的。

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(IPAddress, username=user['username'], password=user['password'])

chan = self.ssh.get_transport().open_session()
chan.settimeout(10800)

try:
    # Execute the given command
    chan.exec_command(cmd)

    # To capture Data. Need to read the entire buffer to capture output
    contents = StringIO.StringIO()
    error = StringIO.StringIO()

    while not chan.exit_status_ready():
        if chan.recv_ready():
            data = chan.recv(1024)
            #print "Indside stdout"
            while data:
                contents.write(data)
                data = chan.recv(1024)

        if chan.recv_stderr_ready():            
            error_buff = chan.recv_stderr(1024)
            while error_buff:
                error.write(error_buff)
                error_buff = chan.recv_stderr(1024)

    exit_status = chan.recv_exit_status()

except socket.timeout:
    raise socket.timeout

output = contents.getvalue()
error_value = error.getvalue()

return output, error_value, exit_status
3

我没有看到和标准输出(stdout)相关的问题,但我不太确定你处理标准错误(stderr)的方式。你能确认一下,是不是捕获标准错误导致了问题吗?我会试试你的代码,然后告诉你结果。

更新:当你执行的命令在标准错误中输出很多信息时,你的代码会卡住。我不太明白为什么,但可能是recv_stderr(600)引起的。所以,捕获错误信息的方式要和捕获标准输出的方式一样。

contents_err = StringIO.StringIO()

data_err = chan.recv_stderr(1024)
while data_err:
    contents_err.write(data_err)
    data_err = chan.recv_stderr(1024)

你可以先试着把recv_stderr(600)改成recv_stderr(1024)或者更大的值。

撰写回答