在远程服务器的日常操作中,常常需要进行文件传输、命令执行等操作。使用手动SSH登录然后执行命令显然不够高效,特别是在需要自动化执行任务时。Python 的 paramiko 库提供了强大的 SSH 客户端功能,能够帮助开发者简化 SSH 连接和文件操作的实现。本文将介绍如何通过封装 paramiko 库,创建一个便于管理和操作的 SSHProxy 类,并通过面向对象的上下文管理方式优化代码结构。
paramiko 是一个用于 SSH 连接和 SFTP 文件传输的 Python 库。通过这个库,你可以在 Python 程序中建立 SSH 连接、远程执行命令、传输文件等。
核心功能:
exec_command 远程执行命令。我们通过封装 paramiko 的 Transport 和 SSHClient,实现了一个简单的 SSHProxy 类,能够简化 SSH 的连接、命令执行和文件上传。下面是代码的详细实现。
pythonimport paramiko
class SSHProxy(object):
    def __init__(self, hostname, port, username, password):
        self.hostname = hostname
        self.port = port
        self.username = username
        self.password = password
        self.transport = None
    def open(self):
        """ 打开SSH连接 """
        self.transport = paramiko.Transport((self.hostname, self.port))
        self.transport.connect(username=self.username, password=self.password)
    def command(self, cmd):
        """ 远程执行命令 """
        ssh = paramiko.SSHClient()
        ssh._transport = self.transport
        stdin, stdout, stderr = ssh.exec_command(cmd)
        result = stdout.read()
        return result
    def upload(self, local_path, remote_path):
        """ 上传文件 """
        sftp = paramiko.SFTPClient.from_transport(self.transport)
        sftp.put(local_path, remote_path)
        sftp.close()
    def close(self):
        """ 关闭SSH连接 """
        self.transport.close()
    def __enter__(self):
        """ 上下文管理协议:进入 """
        self.open()
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        """ 上下文管理协议:退出 """
        self.close()
if __name__ == '__main__':
    with SSHProxy("123.206.16.61", 22, 'root', 'password') as ssh:
        ssh.command('df')
        ssh.upload(r'D:\path\file.txt', '/data/file.txt')
在某些场景下,基于密码的认证不够安全或方便,因此我们可以通过 SSH 密钥认证来连接远程服务器。以下是使用密钥认证的 SSHProxy 实现:
pythonclass SSHProxy(object):
    def __init__(self, hostname, port, username, private_key_path):
        self.hostname = hostname
        self.port = port
        self.username = username
        self.private_key_path = private_key_path
        self.transport = None
    def open(self):
        """ 使用RSA密钥打开SSH连接 """
        private_key = paramiko.RSAKey.from_private_key_file(self.private_key_path)
        self.transport = paramiko.Transport((self.hostname, self.port))
        self.transport.connect(username=self.username, pkey=private_key)
    def close(self):
        """ 关闭SSH连接 """
        self.transport.close()
    def command(self, cmd):
        """ 远程执行命令 """
        ssh = paramiko.SSHClient()
        ssh._transport = self.transport
        stdin, stdout, stderr = ssh.exec_command(cmd)
        result = stdout.read()
        return result
    def upload(self, local_path, remote_path):
        """ 上传文件 """
        sftp = paramiko.SFTPClient.from_transport(self.transport)
        sftp.put(local_path, remote_path)
        sftp.close()
    def __enter__(self):
        """ 上下文管理协议:进入 """
        self.open()
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        """ 上下文管理协议:退出 """
        self.close()
在上述代码中,__enter__ 和 __exit__ 方法实现了上下文管理协议。通过这种方式,我们可以使用 with 语句简化资源管理。
上下文管理协议是 Python 面向对象中的一种特殊协议,允许对象控制 with 语句的行为。当进入 with 语句时,会自动调用 __enter__ 方法;而当退出时,无论是否抛出异常,都会调用 __exit__ 方法来确保资源释放。通过这种机制,我们可以避免忘记关闭资源。
一个简单的上下文管理类实现如下:
pythonclass Context:
    def __enter__(self):
        print('进入上下文')
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('退出上下文')
    def do_something(self):
        print('执行操作')
# 使用上下文管理
with Context() as ctx:
    ctx.do_something()
通过封装 paramiko,我们能够更加高效地管理 SSH 连接,简化了命令执行和文件上传的流程。此外,使用上下文管理协议可以确保资源在使用完毕后正确释放,从而避免内存泄漏或连接未关闭的问题。
这类封装适合于日常自动化任务的执行,比如定期备份、远程日志收集等。通过在代码中合理应用上下文管理协议和封装设计,可以使代码更加简洁和易维护。
Pythonimport paramiko
class SSHProxy(object):
    def __init__(self, hostname, port, username, private_key_path):
        self.hostname = hostname
        self.port = port
        self.username = username
        self.private_key_path = private_key_path
        self.transport = None
    def open(self):
        private_key = paramiko.RSAKey.from_private_key_file(self.private_key_path)
        self.transport = paramiko.Transport((self.hostname, self.port))
        self.transport.connect(username=self.username, pkey=private_key)
    def close(self):
        self.transport.close()
    def command(self, cmd):
        ssh = paramiko.SSHClient()
        ssh._transport = self.transport
        stdin, stdout, stderr = ssh.exec_command(cmd)
        result = stdout.read()
        # ssh.close()
        return result
    def upload(self, local_path, remote_path):
        sftp = paramiko.SFTPClient.from_transport(self.transport)
        sftp.put(local_path, remote_path)
        sftp.close()
    def __enter__(self):
        self.open()
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()
if __name__ == '__main__':
    with SSHProxy('10.211.55.25', 22, 'root', '/Users/wupeiqi/.ssh/id_rsa') as ssh:
        # v1 = ssh.command('sudo ifconfig')
        # print(v1)
        ssh.upload('your.tar', '/data/your.tar')


本文作者:GYC
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!