【问题标题】:Paramiko: how to ensure data is received between commandsParamiko:如何确保在命令之间接收数据
【发布时间】:2014-01-13 03:01:50
【问题描述】:

我正在使用 Paramiko 发出许多命令并收集结果以供进一步分析。每隔一段时间,第一个命令的结果会及时完全返回,并最终出现在第二个命令的输出中。

我正在尝试使用 recv_ready 来解决这个问题,但它不起作用,所以我认为我做错了什么。以下是相关代码:

pause = 1

def issue_command(chan, pause, cmd):
    # send commands and return results
    chan.send(cmd + '\n')
    while not chan.recv_ready():
        time.sleep(pause)
    data = chan.recv(99999)

ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
chan = ssh.connect(host, port=22, username=username, password=password, timeout=3,)

resp1 = issue_command(chan, pause, cmd1)
resp2 = issue_command(chan, pause, cmd2)

这些命令的输出相对较小(几句话)。增加暂停可能会解决问题,但不是理想的解决方案。

任何建议或建议将不胜感激。

【问题讨论】:

    标签: python paramiko


    【解决方案1】:

    我会直接使用transport 并为每个命令创建一个新通道。然后你可以使用类似的东西:

    def issue_command(transport, pause, command):
        chan = transport.open_session()
        chan.exec_command(command)
    
        buff_size = 1024
        stdout = ""
        stderr = ""
    
        while not chan.exit_status_ready():
            time.sleep(pause)
            if chan.recv_ready():
                stdout += chan.recv(buff_size)
    
            if chan.recv_stderr_ready():
                stderr += chan.recv_stderr(buff_size)
    
        exit_status = chan.recv_exit_status()
        # Need to gobble up any remaining output after program terminates...
        while chan.recv_ready():
            stdout += chan.recv(buff_size)
    
        while chan.recv_stderr_ready():
            stderr += chan.recv_stderr(buff_size)
    
        return exit_status, stdout, stderr
    
    ssh = paramiko.SSHClient()
    ssh.load_system_host_keys()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(host, port=22, username=username, password=password, timeout=3,)
    transport = ssh.get_transport()
    pause = 1    
    
    resp1 = issue_command(transport, pause, cmd1)
    resp2 = issue_command(transport, pause, cmd2)
    

    更好的方法是获取命令列表并为每个命令生成一个新通道,轮询每个 chan 的 recv_ready,并在输出可用时吸收它们的 stdout/stderr。 :-)

    编辑:命令退出后读取数据存在潜在问题。请看cmets!

    【讨论】:

    • 我认为这让我走上了正轨。谢谢你。我需要为发出的每个命令创建一个新的连接和传输,因此我将 ssh.connect 和传输语句移到了 issue_command 函数中。到目前为止效果很好。
    • 请注意,这个解决方案可以工作,但不是防弹的——它仍然可以在接收到所有数据之前退出,因为recv_ready() 可以在通道流关闭之前返回False。更多详情:stackoverflow.com/a/39019370/2075565
    • 您的代码中存在竞争条件:在命令退出并且您已检索退出状态后,stdout 或 stderr 缓冲区中可能仍有数据。请看:stackoverflow.com/a/39918539/615987
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    • 2016-04-22
    • 2013-02-22
    • 2022-01-10
    • 1970-01-01
    • 2021-05-05
    相关资源
    最近更新 更多