首页 > 解决方案 > 如何保持 ssh 连接打开并在 python 中执行多个请求和输出

问题描述

因为这个问题似乎针对其他地方,所以我将在这里指出我的问题:

在我的 python 脚本中,我使用 ssh 对远程服务器使用多个请求:

def ssh(command):
  command = 'ssh SERVER "command"'
  output = subprocess.check_output(
    command, 
    stderr=subprocess.STDOUT,
    shell=True,
    universal_newlines=True
  )
  return output

在这里我会得到file1as的内容output

我现在有多种使用此功能的方法:

def show_one():
  ssh('cat file1')

def show_two():
  ssh('cat file2')

def run():
  one = show_one()
  print(one)
  two = show_two()
  print(two)

执行run()将打开和关闭每个show_*方法的 ssh 连接,这使得它非常慢。

解决方案:

  1. 我可以说:
Host SERVER
  ControlMaster auto
  ControlPersist yes
  ControlPath ~/.ssh/socket-%r@%h:%p

进入我的.ssh/config,但我想在 python 中解决这个问题。

  1. 有 ssh 标志-T来保持连接打开,在前面提到的问题中,一个答案是使用它Popen()p.communicate()但是不可能在两者之间获得输出,communicates因为它会引发错误ValueError: Cannot send input after starting communication

  2. 我可以以某种方式更改我的函数以执行单个 ssh 命令,echo "--show1--"; cat file1; echo "--show2--"; cat file2但这对我来说看起来很老套,我希望有更好的方法来保持 ssh 连接打开并像平常一样使用它。

  3. 我想要的:例如一个 pythonic/bashic 做同样的事情,我可以在.ssh/config(见1.)中配置来声明一个特定的套接字用于连接并显式打开、使用、关闭它

标签: pythonssh

解决方案


尝试从类创建 ssh 对象并将其传递给函数:

import paramiko
from pythonping import ping
from scp import SCPClient

class SSH():

def __init__(self, ip='192.168.1.1', username='user', password='pass',connect=True,Timeout=10):
    self.ip = ip
    self.username = username
    self.password = password
    self.Timeout=Timeout
    self.ssh = paramiko.SSHClient()
    self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    if connect:
        self.OpenConnection()
        self.scp = SCPClient(self.ssh.get_transport())

def OpenConnection(self):
    try:
        skip_ping = False
        ping_res=False
        log.info('Sending ping to host (timeout=3,count=3) :'+self.ip)
        try:
            PingRes = ping(target=self.ip,timeout=3,count=3, verbose=True)
            log.info('Ping to host result :' + str(PingRes.success()))
            ping_res=PingRes.success()
        except:
            skip_ping=True
        if ping_res or skip_ping:
            log.info('Starting to open connection....')
            self.ssh.connect(hostname=self.ip, username=self.username, password=self.password, timeout=self.Timeout, auth_timeout=self.Timeout,banner_timeout=self.Timeout)
            self.scp = SCPClient(self.ssh.get_transport())
            log.info('Connection open')
            return True
        else:
            log.error('ssh OpenConnection failed: No Ping to host')
            return False

myssh = SSH(ip='192.168.1.1',password='mypass',username='myusername')

ping 结果包含在 try catch 中,因为有时我的机器会返回错误,您可以将其删除并验证对主机的 ping。self.scp 用于文件传输。


推荐阅读