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

Python Paramiko跨CentOS执行长命令后SSH会话失效问题求助

解决Paramiko长时间会话后出现'SSH session is not active'的问题

我之前处理过类似的场景,长时间空闲的SSH会话很容易被中间防火墙、路由器或者服务器端的超时策略强制断开——哪怕你设置了ServerAlive相关参数,大概率是参数配置的时机或者方式不对,或者会话空闲时间超出了系统容忍的上限。下面给你几个可行的解决方案,按推荐程度排序:

1. 改用后台执行+后续重连检查(最推荐)

既然你的命令要跑10小时,完全没必要一直保持SSH会话挂着。可以让从机器在后台执行命令,主机器记录进程ID后断开连接,10小时后再重新连接检查状态。这种方式彻底规避了会话超时的问题,稳定性最高。

示例代码:

import paramiko
import time

# 第一步:连接并发送后台执行命令
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("slave_host", username="your_user", password="your_pass")

# 用nohup让命令后台运行,同时输出进程ID
long_command = "your_10_hour_command"
command = f"nohup {long_command} > /tmp/command_output.log 2>&1 & echo $!"
stdin, stdout, stderr = ssh.exec_command(command)
# 获取后台进程的PID
pid = stdout.read().decode().strip()
print(f"后台命令已启动,PID: {pid}")

# 断开当前会话
ssh.close()

# 模拟主机器处理其他事务/休眠10小时
time.sleep(36000)

# 第二步:重新连接检查命令状态
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("slave_host", username="your_user", password="your_pass")

# 检查进程是否还在运行
check_command = f"ps -p {pid}"
stdin, stdout, stderr = ssh.exec_command(check_command)
process_exists = stdout.read().strip()

if process_exists:
    print("命令仍在执行中")
else:
    print("命令已执行完成,输出日志如下:")
    stdin, stdout, stderr = ssh.exec_command("cat /tmp/command_output.log")
    print(stdout.read().decode())

ssh.close()

2. 正确配置会话保活参数

如果一定要保持会话不中断,得确保Paramiko的保活参数在正确的时机配置——要在建立连接后、执行命令前,针对Transport对象设置,而不是只在SSHClient层面配置。

示例代码:

import paramiko
import time

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("slave_host", username="your_user", password="your_pass")

# 获取Transport对象并设置保活
transport = ssh.get_transport()
# 每30秒发送一次保活包,避免会话被标记为空闲
transport.set_keepalive(30)

# 执行第一个命令
stdin, stdout, stderr = ssh.exec_command("your_first_command")
# 等待命令完成(如果需要)
stdout.channel.recv_exit_status()

# 主机器处理其他事务/休眠10小时
time.sleep(36000)

# 再次执行命令,此时会话应该保持活跃
stdin, stdout, stderr = ssh.exec_command("your_second_command")
print(stdout.read().decode())

ssh.close()

注意:还要检查从机器的/etc/ssh/sshd_config配置,确保ClientAliveInterval和ClientAliveCountMax的设置不会比你的保活间隔更严格。比如如果服务器端设置ClientAliveInterval 60(60秒没收到客户端响应就发探测包),ClientAliveCountMax 3(发3次没响应就断开),那你的保活间隔要小于60秒,确保服务器端一直能收到客户端的保活信号。

3. 定期发送空命令保持会话活跃

如果上面两种方式都不适用,可以在主机器休眠期间,每隔一段时间给从机器发送一个无副作用的空命令(比如echo ""),强制会话保持活跃。

示例代码:

import paramiko
import threading
import time

def keep_session_alive(ssh):
    while True:
        try:
            # 发送空命令,触发保活
            stdin, stdout, stderr = ssh.exec_command("echo ''")
            stdout.channel.recv_exit_status()
        except Exception as e:
            print(f"保活失败:{e}")
            break
        # 每5分钟发送一次
        time.sleep(300)

# 建立连接
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("slave_host", username="your_user", password="your_pass")

# 启动保活线程
keep_alive_thread = threading.Thread(target=keep_session_alive, args=(ssh,))
keep_alive_thread.daemon = True
keep_alive_thread.start()

# 执行第一个命令
stdin, stdout, stderr = ssh.exec_command("your_first_command")
stdout.channel.recv_exit_status()

# 休眠10小时
time.sleep(36000)

# 执行第二个命令
stdin, stdout, stderr = ssh.exec_command("your_second_command")
print(stdout.read().decode())

ssh.close()

这种方式要注意线程安全,避免和主业务的命令执行冲突。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:36:46