如何用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
相关产品推荐
相关产品推荐

