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

使用Paramiko实现SSH二次连接时遇OSError: Socket is closed问题求助

解决SSH二次跳转的Socket关闭问题

问题背景

已编写Python代码通过Paramiko成功连接到服务器10.218.16.16,现在希望在同一代码中实现从该服务器跳转至hadoopc1h1(模拟Putty中执行ssh user2@hadoopc1h1并输入密码的操作),但运行代码时出现错误:

OSError: Socket is closed

原代码及问题点

第一部分:连接第一台服务器的代码

import paramiko

# Set up SSH client
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# Set up connection details
ip = "10.218.16.16"
user = "user1"
password = "234!!!lem600@HW"

# Connect to server
try:
    ssh.connect(ip, username=user, password=password)
    print(f"Successfully logged in as {ssh.exec_command('whoami')[1].read().decode().strip()}")

except paramiko.ssh_exception.AuthenticationException:
    print("Authentication failed")
    
except paramiko.ssh_exception.SSHException:
    print("Unable to establish SSH connection")
    
finally:
    ssh.close()

第二部分:尝试跳转的代码

ip2 = "hadoopc1h1"
user2 = "user2"
password2 = "235!!!lem600@HW"

try:
    # Execute ssh command to connect to second server
    _, stdout, _ = ssh1.exec_command(f'ssh {user2}@{ip2}')

    stdin = stdout.channel.makefile("wb")
    stdin.write(f"{password2}\n".encode())
    stdin.flush()

    # Print output of ssh command to second server
    print(stdout.read().decode())

核心问题

  1. 变量名错误:跳转代码中使用ssh1,但第一部分连接的客户端实例是ssh,变量名不匹配。
  2. Socket提前关闭:第一部分代码的finally块中直接调用了ssh.close(),导致执行跳转操作时,第一台服务器的SSH连接已关闭,触发Socket is closed错误。
  3. 交互逻辑不可靠:通过exec_command执行ssh后直接写入密码的方式,无法确保命令执行到需要输入密码的阶段,交互逻辑不稳定。

解决方案

方案1:通过Paramiko建立二级SSH连接(推荐)

利用第一台服务器的SSH连接作为跳板,直接建立到第二台服务器的SSH连接,避免交互式输入密码的问题:

import paramiko

# 连接第一台服务器(跳板机)
ip_jump = "10.218.16.16"
user_jump = "user1"
password_jump = "234!!!lem600@HW"

ssh_jump = paramiko.SSHClient()
ssh_jump.set_missing_host_key_policy(paramiko.AutoAddPolicy())

try:
    ssh_jump.connect(ip_jump, username=user_jump, password=password_jump)
    print(f"Successfully logged in to jump server as {ssh_jump.exec_command('whoami')[1].read().decode().strip()}")

    # 通过跳板机建立到目标服务器的TCP通道
    transport = ssh_jump.get_transport()
    dest_addr = ("hadoopc1h1", 22)
    local_addr = (ip_jump, 22)
    channel = transport.open_channel("direct-tcpip", dest_addr, local_addr)

    # 连接目标服务器
    ssh_target = paramiko.SSHClient()
    ssh_target.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh_target.connect("hadoopc1h1", username="user2", password="235!!!lem600@HW", sock=channel)

    # 验证目标服务器连接
    whoami_output = ssh_target.exec_command("whoami")[1].read().decode().strip()
    print(f"Successfully logged in to target server as {whoami_output}")

    # 示例:在目标服务器执行ls命令
    _, stdout, _ = ssh_target.exec_command("ls")
    print("Target server ls output:\n", stdout.read().decode())

except paramiko.ssh_exception.AuthenticationException:
    print("Authentication failed")
except paramiko.ssh_exception.SSHException as e:
    print(f"SSH connection error: {str(e)}")
finally:
    # 关闭所有连接
    if 'ssh_target' in locals():
        ssh_target.close()
    ssh_jump.close()

方案2:修复交互式跳转逻辑(适合简单场景)

如果必须使用交互式ssh命令,调整代码逻辑确保跳板机连接未关闭,并等待密码提示符后再输入密码:

import paramiko
import time

# 连接跳板机
ip_jump = "10.218.16.16"
user_jump = "user1"
password_jump = "234!!!lem600@HW"

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

try:
    ssh.connect(ip_jump, username=user_jump, password=password_jump)
    print(f"Successfully logged in to jump server as {ssh.exec_command('whoami')[1].read().decode().strip()}")

    # 启动交互式shell
    shell = ssh.invoke_shell()
    shell.settimeout(10)

    # 执行跳转命令
    shell.send("ssh user2@hadoopc1h1\n")
    time.sleep(1)

    # 等待密码提示符并输入密码
    while not shell.recv_ready():
        time.sleep(0.5)
    output = shell.recv(1024).decode()
    if "password:" in output:
        shell.send("235!!!lem600@HW\n")
        time.sleep(1)

    # 读取跳转后的输出
    while shell.recv_ready():
        output += shell.recv(1024).decode()
    print("Jump output:\n", output)

except paramiko.ssh_exception.AuthenticationException:
    print("Authentication failed")
except paramiko.ssh_exception.SSHException as e:
    print(f"SSH connection error: {str(e)}")
except Exception as e:
    print(f"Error: {str(e)}")
finally:
    ssh.close()

关键说明

  • 方案1优势:无需处理交互式输入,连接稳定可靠,适合后续在目标服务器执行复杂操作。
  • 方案2注意事项:依赖time.sleep()等待输出,网络延迟较高时可能失效,需根据实际情况调整等待时间。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 00:42:53