【问题标题】:cannot establish connection after reboot重启后无法建立连接
【发布时间】:2020-04-28 14:36:12
【问题描述】:

各位,

我在重新启动后尝试重新连接到服务器时遇到了问题。我看到了其他关于类似问题的文章,但我尝试的所有操作都出现了相同的错误。

目标

重启后自动重新连接服务器

脚本

ssh_client = SSHClient()
ssh_client.set_missing_host_key_policy(AutoAddPolicy())
ssh_client.connect(hostname=host,port=port, username=user, password=psw)
s = ssh_client.get_transport().open_session()
agent.AgentRequestHandler(s)

         try:
            stdin, stdout, stderr = ssh_client.exec_command(command, get_pty= True)
            get_output(stdout)
            channel = stdout.channel
            stdin.close()
            channel.shutdown_write()
            stdout_chunks = []
            stdout_chunks.append(channel.recv(len(channel.in_buffer)))
            while not channel.closed or channel.recv_ready() or channel.recv_stderr_ready():
                got_chunk = False
                readq, _, _ = select.select([stdout.channel], [], [])
                for c in readq:
                    if c.recv_ready():
                        stdout_chunks.append(channel.recv(len(c.in_buffer)))
                        got_chunk = True
                    if c.recv_stderr_ready():
                        stderr.channel.recv_stderr(len(c.in_stderr_buffer))
                        got_chunk = True
                    if not got_chunk \
                            and channel.exit_status_ready() \
                            and not channel.recv_stderr_ready() \
                            and not channel.recv_ready():
                        channel.shutdown_read()
                        channel.close()
                        break
            stdout.close()
            stderr.close()

        except (ConnectionResetError, SSHException):
            print('Connection died')

错误被try catch块缓存:

Connection died
Connection died
Connection died
Connection died
Connection died
Connection died
Connection died
Connection died
Connection died
Connection died
Connection died
Connection died
Connection died
Connection died
Connection died

我在远程服务器上运行的脚本以重启命令结束:

/sbin/shutdown -r now

【问题讨论】:

  • 您的代码 sn-p 缺少尝试。它在哪里?尝试将其放在ssh_client.connect() 之外,以确保您从头开始重新建立连接。
  • 只是复制粘贴错误。将编辑我的帖子。如您所见,它在@Hannu 之外
  • 重启后,通常需要启动httpd服务和mysql服务才能使web服务器正常运行。检查是否是您的情况。
  • 这两个服务在每次重启后都会自动启动。我也通过 SSH 连接,据我所知服务器不应该运行 httpd 或 mysqld 以便重新连接。如果我错了,请纠正我:) @Kosem
  • 我不明白为什么这两行没有帮助 s=ssh.get_transport().open_session() #get 'ssh' 传输并打开分配给 's' 变量 paramiko.agent.AgentRequestHandler 的会话(s) #call in 's' 到当前 ssh 会话的转发代理

标签: python paramiko reboot


【解决方案1】:

我会将其作为答案发布,因为它太长而无法在评论中解释。

您的代码仍然缺少部分,因为我们不知道您如何调用 try/except 结构以及捕获异常时会发生什么。但是,如果我可以从您的缩进中猜测是,如果捕获到异常,您将以某种方式重复 try/except。

您的逻辑中似乎依赖于通道关闭状态,但有一个 TCP 套接字形式的底层。当您重新启动服务器时,您的通道会死掉,但 TCP 层也会死掉。在您的异常处理中,您需要重新创建它。

我会尝试这样的:

try:
    ...
    ...
    ...
    stdout.close()
    stderr.close()
except (...):
    sleep(2)  # to prevent a busyloop when your server is rebooting      
    try:
        ssh_client.close()  # Close the connection just in case it is alive
    except:
        pass    # We do not care if it succeeds or fails
    counter = 0     # optional
    while True:
        sleep(2)    # to prevent a busyloop when your server is rebooting
        counter += 1
        if counter > X:
            print("server permanently down, exiting")
            exit (1)
        try:
            ssh_client.connect(hostname=host,port=port, username=user, password=psw)
            s = ssh_client.get_transport().open_session()
            break    # We have a liftoff
        except:
            pass     # Server not responding yet. Try again. 

(上面的代码我没有测试,只是写在这里给出思路,可能有错别字)

您可以忽略计数器部分。如果服务器长期停机,我通常使用计数器来防止程序尝试直到奶牛回家。如果您想继续尝试,请删除这些。如果您使用它们,只需将 X 设置得足够高,以允许服务器有足够的时间重新启动,然后再重新启动一些。

关键部分是在发生错误后重新创建您的 TCP 连接,并且仅在您再次有工作连接时才离开错误处理程序。

我们会尝试关闭现有连接,以防它仍然存在,以避免在问题不在连接断开时耗尽服务器资源,但我们不关心它是成功还是失败。然后我们从头开始重新创建连接。

这可能适用于您的情况,也可能不适用,因为我们从您的代码中不知道您在出现异常后如何重新输入 - 而且您似乎也不确定是否基于您的 cmets。

【讨论】:

  • 谢谢。通过将 ssh_client.get_transport() is not None 添加到 if 语句和 if 是重新连接来修复它。
  • 很好用。不过,这可能不是万无一失的方法。如果这是一个繁忙的环境,最终会发生意外,并且您的服务器会在您的新 if 语句和其余代码之间停止运行。检查时传输已启动,但当您尝试发送时不再传输。现在您的客户端将再次以异常处理程序结束。如果下一次迭代符合您的get_transport() 检查,那么您的代码可能也适用于这种情况。只是要记住的事情。
猜你喜欢
  • 1970-01-01
  • 2021-03-28
  • 2011-05-29
  • 1970-01-01
  • 2019-12-26
  • 2015-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多