热心冰块
作者热心冰块·2022-03-31 20:05
项目经理·浪潮INSPUR

应近水楼台同学要去写的:SSH登陆注释版本

字数 5843阅读 1796评论 0赞 1

应站内兄弟#近水楼台#的要求,吧之前发的代码加了注释,因此这个也就算不上什么文章了,新坛装老酒罢了。所以我就闲扯两句,最近无聊心血来潮下了一个MS VS2022,以为C#会继承C/C++的很多东西,我中学是自学的第一个编程语言就是C。结果……边查边写边玩的过程中发现C#和C/C++唯一的关系就是名字里有C……
无聊的我写了个IPv4的子网计算器,还没研究IPv6,所有只能算是半成品,需要源码的单独找我吧,程序也可以找我要。 .net4.8可运行
突然顿悟了一下,现在这五花八门的各种程序语言,越来越吧一个庞大的构想,分解分解再分解,不断的给这个庞大构想制作各种小工具——自定义的函数或者类,然后一拼吧,嚯!!!成了!

#!/usr/bin/env python            #Linux里的写法,用了声明这个脚本是什么语言的
# -*- coding:utf-8 -*-            #用来声明字符集


import paramiko     # SSH操作的主模块
import paramiko.util    # 我主要用来做SSH Log用
import multiprocessing  # 多进程模块


class SSHTransport(object):
    def __init__(self, host, port, username, password):
        # 构造函数,类调用即执行
        # self。xxx是类里特有的,可以简单理解成告诉类,有self的是我自己的变量,函数,没有的都是外人的
        # 一般需要在类里使用的变量我都在析构函数__init__里声明一下,暂时无法赋值的就 = None,反正Python支持隐形类型转换
        # 下面4条是将传进来的参数存储到类本地的变量里
        self._host = host
        self._port = port
        self._username = username
        self._password = password

        # 初始化3个用于存储SSH初始化、SFTP、SSH连接的变量
        self._transport = None
        self._sftp = None
        self._client = None

        # 调用函数:_connect()
        self._connect()

    def _connect(self):
        # 本函数用于生成连接的套接字
        # 设置SSH操作日志文件
        paramiko.util.log_to_file("D:\\SSH_Connect.log")
        # 初始化连接
        transport = paramiko.Transport((self._host, self._port))
        # 发起连接
        transport.connect(username=self._username, password=self._password)
        # 连接句柄存储,方便其他函数调用
        self._transport = transport

    def download(self, remotepath, localpath):
        if self._sftp is None:
            # 如果sftp没创建过套接字则创建一个,都是固定格式
            self._sftp = paramiko.SFTPClient.from_transport(self._transport)
        # 利用套接字_sftp的get方法下载文件,参数我都用英文写的应该比较好理解
        self._sftp.get(remotepath, localpath)

    def upload(self, localpath, remotepath):
        if self._sftp is None:
            #同上,判断创建过套接字没,没有就创建一个
            self._sftp = paramiko.SFTPClient.from_transport(self._transport)
        # 调用put方法上传
        self._sftp.put(localpath, remotepath)

    def exec_command(self, command):
        if self._client is None:
            # 同上,SSH套接字没创建就创建一个
            # 创建客户端套接字
            self._client = paramiko.SSHClient()
            # 创建连接,将之前做好的连接套接字拿过来用就可以
            self._client._transport = self._transport
        # 发送命令,会返回三个元素的(应该是List类型的结果,没太细研究,只知道这么用),stdin是标准输入,stdout是标准输出,
        # stderr是标准报错,不这样写有错误会直接咯嘣
        stdin, stdout, stderr = self._client.exec_command(command)
        # 声明一个list类型变量,这个类型是我超级喜欢的类型,太好用了
        re = list()
        for Line in stdout.readlines():
            # 用循环按行读取标准输出
            # 读取的文本行写入到刚刚声明的List类型变量中
            # [:-1]的意思是从左边开始读取,但舍弃最右边的一个字符,这里具体的意思就是把换行符给干掉
            re.append(Line[:-1])
        return re

    def close(self):
        if self._transport:
            # 如果这个套接字不是空的,逻辑值就是true的,就需要执行close关闭他,有始有终是个好习惯
            self._transport.close()
        if self._client:
            # 同上
            self._client.close()


def login_info(file_name):
    # 声明变量
    login_info = list()
    host_info = list()
    with open(file_name, "r")as f:
        # with open是打开文件的一种方式,我比较喜欢这样的方式,感觉比较帅的一个打开方式
        for Line in f.read().splitlines():
            # 循环按行读取文件内容
            match len(host_info):
                # match好像是在3.8,应该是3.8版本里新加的一个关键字,拿C举例,在面向过程的代码里,三个重要的过程控制关键字类就是:
                # 判断、循环、分支。这里用到的就是分支,在3.8之前是不支持的,只能用if去做替代
                # 这里要做的吧用户名,密码、端口、IP四个信息读取进来,存在临时变量host_info里
                case 0:
                    host_info.append(Line)
                case 1:
                    host_info.append(int(Line))
                case 2:
                    host_info.append(Line)
                case 3:
                    host_info.append(Line)
                    # 存满了一套登陆信息就插入到Login_info变量里,看到了吧,我非常喜欢List类型,写的东西大量应用list类型变量
                    login_info.append(host_info)
                    # 保存了条登陆信息,host_info这个临时变量的内容就没用了,用声明的方法来初始化一下
                    host_info = list()
        # 把登陆信息作为函数的返回值传递
        return login_info


def comm_info(file_name):
    # 声明list变量用来存储命令
    comm_info = list()
    with open(file_name, "r")as f:
        # 读取存储命令的文件,方法同上,不用过多解释了,唯一不同的就是命令文件是一行一条命令,不用做4行切分
        for Line in f.read().splitlines():
            comm_info.append(Line)
    return comm_info


class mp_start(object):
    # 用来做多进程的类
    def __init__(self, hosts_info):
        # 构造函数
        # 初始化套接字存储到conn中,host_info是调用类时传递进来的参数,前四个元素是登陆信息
        conn = SSHTransport(hosts_info[0], hosts_info[1], hosts_info[2], hosts_info[3])
        # 存结果的临时变量,有事list类型
        re = list()
        # 添加一行,记录下IP
        re.append("IP Address is: " + hosts_info[0])
        for comm in hosts_info[4]:
            #第五个元素个List类型的元素,也就是说我吧List做成了二维的,哈哈
            # 在结果中记录下命令体
            re.append("---=== Command is: " + comm)
            for Line in conn.exec_command(comm):
                # 调用conn也就是我之前做的SSHTransport类的exec_command方法来执行命令,用for循环来按行处理结果,外层循环是循环的登陆信息
                # 内层循环跑的命令集,结果就是所有的登陆信息都执行了所有的命令,当然这里我没做不对称的二维hosts_info,也就是不通的登陆信息执行
                # 不同的命令集,我只做了同质化的示例
                re.append(Line)     # 存储结果行
        # 有始有终是个好孩子
        conn.close()
        # 添加空行
        re.append("")
        # 向屏幕打印结果
        for Line in re:
            print(Line)


if __name__ == "__main__":
    #这里就是程序的入口了
    # 这条if的作用是判断下程序是被引用的,还是执行的,如果是执行的,就执行下面一段
    # 声明变量,还是List类型哈
    hosts_info = list()
    comms_info = list()

    for Line in comm_info("Command.ini"):
        # 调用之前定义好的函数,吧命令都存起来
        comms_info.append(Line)

    for Line in login_info("LoginInfo.ini"):
        # 调用定义好的函数把登陆信息都存起来这两条for是为了满足多进程要求而做的
        hosts_info.append([Line[0], Line[1], Line[2], Line[3], comms_info])

    with multiprocessing.Pool() as p:
        # 上一条固定格式,调用多进程模块
        # 下一条常用格式,mp_start是进程启动的函数, hosts_info是参数,List类型,这样灌进去,剩下的就交给命运来安排就好了
        print(p.map(mp_start, hosts_info))

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

1

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广