• 老男孩Day12作业:RabbitMQ-RPC版主机管理程序


    一、作业需求

    1、可以对指定机器异步的执行多个命令

    例子:
    请输入操作指令>>>:run ipconfig --host 127.0.0.0
    in the call     tack_id:[24869c59-bdc3-4cfc-9a00-313e257d9f58]     cmd:[ipconfig]      host:[127.0.0.0]

    >请输入操作指令>>>:check_all
    查看所有任务编号:
    1     24869c59-bdc3-4cfc-9a00-313e257d9f58
    2     f2d05df2-05b7-4059-93cc-de7c80aee5af

    请输入操作指令>>>:check_task 24869c59-bdc3-4cfc-9a00-313e257d9f58
    查看任务[24869c59-bdc3-4cfc-9a00-313e257d9f58]返回结果:
    Windows IP 配置


    以太网适配器 本地连接:

       连接特定的 DNS 后缀 . . . . . . . :
       本地链接 IPv6 地址. . . . . . . . : fe80::cddb:da51:7e58:2515%11
       IPv4 地址 . . . . . . . . . . . . : 192.168.1.119

    二、readme

    一、作业需求:
    
    1、可以对指定机器异步的执行多个命令
    
    例子:
    请输入操作指令>>>:run ipconfig --host 127.0.0.0
    in the call     tack_id:[24869c59-bdc3-4cfc-9a00-313e257d9f58]     cmd:[ipconfig]      host:[127.0.0.0]
    
    请输入操作指令>>>:run dir --host 127.0.0.0
    in the call     tack_id:[f2d05df2-05b7-4059-93cc-de7c80aee5af]     cmd:[dir]      host:[127.0.0.0]
    
    >请输入操作指令>>>:check_all
    查看所有任务编号:
    1     24869c59-bdc3-4cfc-9a00-313e257d9f58
    2     f2d05df2-05b7-4059-93cc-de7c80aee5af
    
    请输入操作指令>>>:chedk_task 24869c59-bdc3-4cfc-9a00-313e257d9f58
    
    请输入有效操作指令
    
    请输入操作指令>>>:check_task 24869c59-bdc3-4cfc-9a00-313e257d9f58
    
    
    注意,每执行一条命令,即立刻生成一个任务ID,不需等待结果返回,通过命令check_task TASK_ID来得到任务结果
    
    二、博客地址:http://www.cnblogs.com/catepython/p/9051490.html
    
    三、运行环境
    
    操作系统:Win10
    
    Python:3.6.4rcl
    
    Pycharm:2017.3.4
    
    四 、具体实现
    思路解析:
    
    分析需求其实可以发现,输入命令为消费者,执行命令是生产者,参照RabbitMQ的官方文档rpc部分和课上的代码就可以了。
    
    1. 使用RabbitMQ_RPC, Queen使用主机IP
    
    2. 消费者输入命令,分割字段,获取run,check_task,check_task_all,host等信息,传给生产者。
    
    3. 生产者执行命令处理windows/linux不同消息发送情况windows decode(‘gbk’) linux decode('utf-8'),返回结果。
    
    4. 消费者将结果存成字典,查询结果后删除。 
    
    五、测试流程
    
    1、在本次作业中处理了各种操作指令的异常处理 如:数组越界、使用check_task操作时无效任务ID处理
    
    2、对用户输入的格式就行了正则 如:IP地址格式的判断
    
    3、同时能对多个服务主机发送并接收相应的数据信息
    
    六、备注
    1、完成本次作业看了5遍视频,百度了所有大神们的心得代码,终于理清了整个RPC框架和原理
    readme

    三、流程图

    四、目录结构图

    五、核心代码

    conf目录

    #-*-coding:utf-8 -*-
    # Author: D.Gray
    
    import os
    
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    LOCAL_HOST = ('localhost')
    setting

    core主逻辑目录

    #-*-coding:utf-8 -*-
    # Author: D.Gray
    
    import pika,uuid,time,re
    from conf import setting
    
    class Producer(object):
        def __init__(self):
            self.connaction = pika.BlockingConnection(pika.ConnectionParameters(setting.LOCAL_HOST))
            self.channel = self.connaction.channel()
            self.result = self.channel.queue_declare(exclusive=True)    #生产一个随机queue
            self.callback_queue = self.result.method.queue
            # 声明一个queue,一收到消息就调用on_response函数
            self.channel.basic_consume(self.on_response,no_ack=True,queue=self.callback_queue)
    
        def on_response(self,ch,method,props,body):
            '''
            处理收到消息函数
            :param ch:
            :param method:
            :param props:
            :param body:
            :return:
            '''
            if self.corr_id == props.correlation_id:
                self.response = body
    
        def call(self,cmd,host):
            '''
            发送操作指令至服务端函数
            :param cmd:
            :param host:
            :return:
            '''
            self.response = None
            self.corr_id = str(uuid.uuid4())
    
            #把操作指令发送给服务端,并把与服务端约定好一个随机queue一同传过去
            self.channel.basic_publish(exchange='',routing_key=host,
                                       properties=pika.BasicProperties(
                                           reply_to=self.callback_queue, #与服务端约定好一个随机queue进行第二次数据交互
                                           correlation_id = self.corr_id
                                       ),
                                       body=str(cmd)
                                       )
    
            while self.response is None:
                self.connaction.process_data_events()   #非阻塞版的start_consume
                # print('no message...')
                # time.sleep(1)
            task_id = self.corr_id
            res = self.response.decode()
            tmp_dict[task_id] = res
            print('in the call	 tack_id:[%s]	 cmd:[%s]	  host:[%s]'%(task_id,cmd,host))
            return task_id,res
    
    def help():
        '''
        帮助函数
        :return:
        '''
        meg = '''33[32;1m
        run "df -h" --hosts 127.0.0.1 192.168.84.66:执行操作命令格式
        check_task 54385061-aa3a-400f-8a21-2be368e66493:查看某个任务id返回结果
        check_all:查看所有任务编号
        33[0m'''
        print(meg)
    
    def checkip(ip):
        '''
        正则判断参数是否是IP地址格式
        :param ip: 需判断的字符串
        :return:
        '''
        p = re.compile('^((25[0-5]|2[0-4]d|[01]?dd?).){3}(25[0-5]|2[0-4]d|[01]?dd?)$')
        if p.match(ip):
            return True
        else:
            return False
    
    def start(cmd):
        '''
    
        :param cmd:
        :return:
        '''
        #print('in the start:',cmd)
        if cmd[0] == 'run':
            if len(cmd) > 3:
                hosts = cmd[3:]
                for host in hosts:
                    if checkip(host) is True:   #调用checkip方法来判断参数是否符合IP地址格式
                        try:
                            cmd_rpc.call(cmd[1],host)   #把操作指令和ip 传给call()方法去解析
                        except Exception as e:
                            print('33[31;1m有异常报错:33[0m', e)
                            help()
                    else:
                        print('33[31;1m请输入有效IP地址33[0m')
                        help()
            else:
                print('33[31;1m请正确输入有效指令')
                help()
        elif cmd[0] == 'help':
            help()
        elif cmd[0] == 'check_all':
            if len(tmp_dict) == 0:
                print('33[31;1m暂无任务ID33[0m')
            else:
                print('查看所有任务编号:')
                for index,key in enumerate(tmp_dict.keys()):
                    print('%s	 %s'%(index+1,key))
        elif cmd[0] == 'check_task':
            try:
                print('查看任务[%s]返回结果:%s'%(cmd[1],tmp_dict[cmd[1]]))
                del tmp_dict[cmd[1]]
            except IndexError as e:
                print('33[31;1m数组越界:33[0m',e)
                help()
            except KeyError as e:
                print('33[31;1m无效任务ID:33[0m',e)
        else:
            print('33[31;1m请输入有效操作指令33[0m')
    
    cmd_rpc = Producer()
    tmp_dict = {}
    while True:
        cmd_input = input('请输入操作指令>>>:').strip().split()
        if len(cmd_input) == 0:continue
        else:
            start(cmd_input)
    客户端
    #-*-coding:utf-8 -*-
    # Author: D.Gray
    import pika
    import subprocess
    import platform
    connaction = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connaction.channel()
    channel.queue_declare(queue='127.0.0.0')    #设置一个队列与客户端首次交互
    
    os_res = platform.system()
    def command(cmd):
        if os_res == 'Windows':
            res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            msg = res.stdout.read().decode('gbk')
            if len(msg) == 0:
                msg = res.stderr.read().decode('gbk')
            #print(msg)
            return msg
    
        else:
            res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            #print(res)
            msg = res.stdout.read().decode()
            if len(msg) == 0:
                msg = res.stderr.read().decode()
            return msg
    
    def on_response(ch,method,props,body):
        '''
        处理客户端传来消息的函数
        :param ch:
        :param method:
        :param props:
        :param body:
        :return:
        '''
        cmd = body.decode()
        #('收到客户端传来参数:[%s]'%cmd)
        response = command(cmd)         #调用command函数来解析函数
    
        ch.basic_publish(exchange='',routing_key=props.reply_to,    #把消息传到与客户端约定好的随机queue中
                                properties=pika.BasicProperties(correlation_id = props.correlation_id),
                         body = str(response))
    
        ch.basic_ack(delivery_tag=method.delivery_tag)  #手动确认消息有无被消费掉
    
    
    #监听1270.0.0这个队列一收到客户端传来的消息就调用on_response处理消息
    channel.basic_consume(on_response,queue='127.0.0.0')
    print('等待客户端传来求值参数...')
    channel.start_consuming()
    服务端
  • 相关阅读:
    Pytest权威教程21-API参考-02-标记(Marks)
    GitLab获取人员参与项目-贡献项目列表
    通过Confulence API统计用户文档贡献量
    Git项目代码统计-Python3版gitstats
    Pytest从测试类外为测试用例动态注入数据
    Python操作Jira
    Selenium操作Chrome模拟手机浏览器
    剑指offer 构建乘积数组
    栈与堆 && char*, char[], char**, char*[], char[][]详解
    vector 容器知识点汇总
  • 原文地址:https://www.cnblogs.com/catepython/p/9051490.html
Copyright © 2020-2023  润新知