Python Paramiko超时执行时间长,需要完整输出

use*_*459 5 python ssh timeout paramiko

有很多主题涉及标题的一部分,但没有任何东西可以完全满足整个事情.我在远程服务器上推送一个命令,经过很长的执行时间后需要完整的输出,比如5分钟左右.使用通道我能够设置超时,但是当我读回stdout时,我只得到了一小部分输出.解决方案似乎是等待channel.exit_status_ready().这对成功的呼叫起作用,但是失败的呼叫永远不会触发信道超时.在查看了文档之后,我推测这是因为超时仅适用于读取操作,并且等待退出状态不符合条件.这是尝试:

channel = ssh.get_transport().open_session()
channel.settimeout(timeout)
channel.exec_command(cmd)  # return on this is not reliable
while True:
    try:
        if channel.exit_status_ready():
            if channel.recv_ready():  # so use recv instead...
                output = channel.recv(1048576)
                break
        if channel.recv_stderr_ready():  # then check error
            error = channel.recv_stderr(1048576)
            break
    except socket.timeout:
        print("SSH channel timeout exceeded.")
        break
    except Exception:
        traceback.print_exc()
        break
Run Code Online (Sandbox Code Playgroud)

漂亮,不是吗?希望它有效.

我第一次尝试解决方案是使用time.time()来启动,然后检查start - time.time()> timeout.这看起来很简单,但在我目前的版本中,我输出start-time.time(),其中一个固定的超时应该触发一个中断...并且看到差异使得超时加倍并且不会发生中断.为了节省空间,我会提到我的第三次尝试,我已经用这个尝试了.我在这里读到关于使用select.select等待输出的问题,并在文档中注意到那里也有超时.正如您将从下面的代码中看到的那样,我混合了所有三种方法 - 通道超时,time.time超时和选择超时 - 但仍然必须终止进程.这是frankencode:

channel = ssh.get_transport().open_session()
channel.settimeout(timeout)
channel.exec_command(cmd)  # return on this is not reliable
print("{0}".format(cmd))
start = time.time()
while True:
    try:
        rlist, wlist, elist = select([channel], [], [],
            float(timeout))
        print("{0}, {1}, {2}".format(rlist, wlist, elist))
        if rlist is not None and len(rlist) > 0:
            if channel.exit_status_ready():
                if channel.recv_ready():  # so use recv instead...
                    output = channel.recv(1048576)
                    break
        elif elist is not None and len(elist) > 0:
            if channel.recv_stderr_ready():  # then check error
                error = channel.recv_stderr(1048576)
                break
        print("{0} - {1} = {2}".format(
            time.time(), start, time.time() - start))
        if time.time() - start > timeout:
            break
    except socket.timeout:
        print("SSH channel timeout exceeded.")
        break
    except Exception:
        traceback.print_exc()
        break
Run Code Online (Sandbox Code Playgroud)

这是一些典型的输出:

[<paramiko.Channel 3 (open) window=515488 -> <paramiko.Transport at 0x888414cL (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>], [], []
1352494558.42 - 1352494554.69 = 3.73274183273
Run Code Online (Sandbox Code Playgroud)

顶行是select的[rlist,wlist,elist],底行是time.time() - start =(time.time() - start).通过计算迭代次数并在循环1000次后尝试在底部打破,我得到了这个运行.样本运行时超时设置为3.这证明我们通过了尝试,但显然,三种方式都不应该超时.

如果我从根本上误解了某些东西,请随意撕掉代码.我希望这是超级 - Pythonic,我还在学习.

Fin*_*ers 2

我也有同样的问题。我认为我们可以通过信号来处理它。http://docs.python.org/2/library/signal.html

这是一个简单的愚蠢示例来展示它是如何工作的。

import signal, time                          

def handler(signum, frame):                  
    pass                                     

# Set the signal handler and a 2-second alarm
signal.signal(signal.SIGALRM, handler)       
signal.alarm(2)                              

# This is where your operation that might hang goes
time.sleep(10)                               

# Disable the alarm                          
signal.alarm(0)                              
Run Code Online (Sandbox Code Playgroud)

所以这里,闹钟设置为2秒。Time.sleep 在 10 秒内被调用。当然,闹钟会在睡眠结束之前触发。如果您在 time.sleep 之后放置一些输出,您将看到程序执行在那里恢复。

如果您希望控件在其他地方继续,请将挂起的调用包装在 try/ except 中,并让处理函数引发异常。

虽然我很确定它会起作用,但我还没有通过 paramiko 调用测试它。