You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python实现跳板机嵌套SSH连接多台远程主机并修复代码卡死问题

代码问题根因
  • 缓冲区接收逻辑错误:原代码每次调用chan.recv()直接覆盖buff变量,之前收到的内容全部丢失,永远无法匹配到password:、$ 等结束标志,导致程序永久阻塞在recv调用。
  • 密码发送逻辑位置错误:密码发送语句写在了等待密码提示的循环内部,还没确认收到密码提示就会反复发送密码,逻辑完全混乱。
  • 通道关闭时机错误:chan.close()写在IP遍历循环内部,第一个远程主机执行完成后直接关闭跳板机的交互通道,后续IP完全无法使用该通道。
  • 没有设置通道超时,遇到网络异常会无限制阻塞。
修正后完整代码
import paramiko

# 配置参数
JUMP_HOST = '10.141.21.239'
JUMP_PORT = 22
JUMP_USER = 'admin'
JUMP_PWD = 'admin'
REMOTE_USER = 'user'
REMOTE_PWD = 'Password'
REMOTE_IPS = ['10.154.65.186','10.154.65.187','10.154.65.188','10.154.65.189','10.154.65.190']

def recv_until(chan, end_str, timeout=10):
    """封装接收直到匹配结束标志的通用方法,避免重复代码"""
    chan.settimeout(timeout)
    buff = b''
    while not buff.endswith(end_str.encode()):
        try:
            recv_data = chan.recv(4096)
            if not recv_data:
                raise Exception("通道已关闭,接收数据失败")
            buff += recv_data
            print(recv_data.decode(), end='')
        except TimeoutError:
            raise Exception(f"等待{end_str}超时,当前接收内容:{buff.decode()}")
    return buff

if __name__ == '__main__':
    # 连接跳板机
    ssh = paramiko.SSHClient()
    ssh.load_system_host_keys()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(JUMP_HOST, JUMP_PORT, JUMP_USER, JUMP_PWD)

    # 开启交互式shell
    chan = ssh.invoke_shell()
    # 等待跳板机提示符
    recv_until(chan, '$ ')

    # 执行跳板机ifconfig命令
    chan.send('ifconfig\n')
    recv_until(chan, '$ ')

    # 循环连接远程主机
    for ip in REMOTE_IPS:
        print(f"\n===== 开始处理远程主机 {ip} =====")
        # 发起ssh连接请求
        chan.send(f'ssh {REMOTE_USER}@{ip}\n')
        
        try:
            # 等待密码提示,处理主机密钥错误
            buff = recv_until(chan, 'password: ')
        except Exception as e:
            if "Host key verification failed" in str(e):
                # 清除旧的主机密钥
                chan.send(f'ssh-keygen -f "/home/admin/.ssh/known_hosts" -R "{ip}"\n')
                recv_until(chan, '$ ')
                # 重新发起ssh连接
                chan.send(f'ssh {REMOTE_USER}@{ip}\n')
                recv_until(chan, 'password: ')
            else:
                raise e
        
        # 输入远程主机密码
        chan.send(f'{REMOTE_PWD}\n')
        # 等待远程主机提示符
        recv_until(chan, '$ ')

        # 执行远程主机命令
        chan.send('ls -lrt\n')
        recv_until(chan, '$ ')

        chan.send('ifconfig -a\n')
        recv_until(chan, '$ ')

        # 退出远程主机ssh会话,回到跳板机
        chan.send('exit\n')
        recv_until(chan, '$ ')
        print(f"===== 远程主机 {ip} 处理完成 =====")

    # 所有操作完成后关闭通道和连接
    chan.close()
    ssh.close()
核心修改说明
  • 封装了通用的recv_until方法,每次接收数据追加到缓冲区,避免内容丢失,同时增加超时机制防止永久阻塞
  • 调整了密码发送的逻辑,只有确认收到密码提示后才发送密码
  • 将通道关闭逻辑移到循环外部,所有远程主机处理完成后再关闭通道
  • 优化了主机密钥错误的处理逻辑,异常捕获更准确
  • 拆分了配置参数,后续修改更方便

内容的提问来源于stack exchange,提问作者user17440807

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 13:36:09