基于RabbitMQ的direct任务驱动异步RPC程序实现:

RPC_dispatcher指令分发器:

 #!/usr/bin/env python
# -*- coding:utf-8 -*-
__Author__ = "Zhang Xuyao" import pika
import uuid
import time
import threading class RpcDispatcher(object):
def __init__(self, rMQ_addr):
self.cmd_list = [
"ls", "df", "free",
"ip", "ifconfig", "tail",
"head", "grep", "uptime",
"date"
]
self.task_dict = {}
self.task_fin_dict = {}
self.routing_key_list = [] self.connection = pika.BlockingConnection(
pika.ConnectionParameters(host=rMQ_addr)
)
self.channel = self.connection.channel() # 收数据用
recv_queue = self.channel.queue_declare(exclusive=True)
self.recv_queue_name = recv_queue.method.queue
self.channel.basic_consume(self._on_response, queue=self.recv_queue_name) # 发数据用
self.channel.exchange_declare(exchange='send', type='direct')
self.send_queue = self.channel.queue_declare()
self.send_queue_name = self.send_queue.method.queue # 获取指定通道的响应(4)###
def _on_response(self, ch, method, parameters, msg):
if parameters.correlation_id in self.task_dict:
self.task_dict[parameters.correlation_id][parameters.app_id]["response"] = msg.decode("utf-8")
ch.basic_ack(delivery_tag=method.delivery_tag)
self.task_dict[parameters.correlation_id][parameters.app_id]["recv_time"] = time.time()
fin_flag = False
for host in self.task_dict[parameters.correlation_id]:
if self.task_dict[parameters.correlation_id][host]["response"] != None:
continue
else: break
# 执行结果全部收到就把记录转移到已经完成容器中,根据检查已经完成容器中的内容用于确定任务的状态
else:
self.task_fin_dict[parameters.correlation_id] = self.task_dict[parameters.correlation_id]
del self.task_dict[parameters.correlation_id] # 发送请求(2)######
def _on_request(self, input_cmd, host_list):
print(RpcDispatcher.colorStr("[x]Requesting>>: '%s' on %s"
% (cmd, tuple(host_list)), 33))
self.response = None
# 生成全局校验码
corr_id = str(uuid.uuid4())
print(RpcDispatcher.colorStr("[x]Task_id>>: %s"
% corr_id, 34))
self.task_dict[corr_id] = {}
if host_list:
for host in host_list:
self.task_dict[corr_id][host] = {
"cmd": input_cmd,
"response": None,
"req_time": time.time(),
"recv_time": None,
}
# 绑定routing_key准备并发布消息
self.channel.queue_bind(exchange='send',
queue=self.send_queue_name,
routing_key=host)
# 向执行器并发布消息指令
self.channel.basic_publish(exchange='send',
routing_key=host,
properties=pika.BasicProperties(
reply_to=self.recv_queue_name,
correlation_id=corr_id,
),
body=str(input_cmd))
# 消息发布后解除routing_key绑定
self.channel.queue_unbind(exchange='send',
queue=self.send_queue_name,
routing_key=host) # 守护线程负责不断检测响应结果是否全部收到
on_recv_thread = threading.Thread(target=self._on_recv, args=[corr_id, ])
on_recv_thread.setDaemon(True)
on_recv_thread.start() # 等待数据消息(3)
def _on_recv(self, task_id):
# 根据检查已经完成容器中的指定task_id是否存在来确定任务的状态,为空则继续收取消息
while task_id not in self.task_fin_dict:
self.connection.process_data_events() # 显示已经完成的任务编号(5)
def show_task_fin(self):
print("尚未查看的任务:")
for task_id in self.task_fin_dict:
value_list = tuple(self.task_fin_dict[task_id].values())
host_list = tuple(self.task_fin_dict[task_id].keys())
cmd = str(value_list[0]["cmd"])
print(RpcDispatcher.colorStr("[task_id]: %s | [cmd_info]: '%s' | [host_list]: %s"
% (task_id, cmd, host_list), 32)) # 获取指定任务的执行结果(6)
def get_response(self, task_id):
if task_id in self.task_fin_dict:
for host in self.task_fin_dict[task_id]:
response = self.task_fin_dict[task_id][host]["response"]
cmd_req = self.task_fin_dict[task_id][host]["cmd"]
time_cost = self.task_fin_dict[task_id][host]["recv_time"] - \
self.task_fin_dict[task_id][host]["req_time"]
time_cost = round(time_cost, 3)
print(RpcDispatcher.colorStr("Host: %s | Cmd: '%s' \nTime Cost: %ss | Response: "
% (host, cmd_req, time_cost), 33))
print(RpcDispatcher.colorStr(response, 36))
del self.task_fin_dict[task_id]
else:
print("任务结果尚未全部返回") # 接收外部输入,调用请求(1)
def call(self, cmd, host_list):
return self._on_request(cmd, host_list) @staticmethod
def colorStr(aStr, color_code):
return "\033[0;" + str(color_code) + ";0m" + aStr + "\033[0m" def __del__(self):
self.connection.close() if __name__ == '__main__':
cmd_rpc = RpcDispatcher(rMQ_addr="localhost")
while True:
cmd = input("[$]Cmd>>:")
if cmd.lower() != 'eof' and cmd.lower() != 'exit':
if cmd.split()[0].lower() in ["$s"]:
cmd_rpc.show_task_fin()
elif cmd.split()[0].lower() in ["$c"] and len(cmd.split()) == 2:
cmd_rpc.get_response(cmd.split()[1])
else:
cmd_split = cmd.split()
has_host = cmd_split.count("--hosts")
if has_host != 1:
print(cmd_rpc.colorStr("Usage <cmd> --hosts <ip1>[,<ip2>[,<ip3>...]]", 35))
continue
else:
if len(cmd_split) <= cmd_split.index("--hosts") + 1:
print("请至少指定一个主机IP")
continue
host_list = cmd_split[cmd_split.index("--hosts") + 1].split(',')
cmd = " ".join(cmd_split[0:cmd_split.index("--hosts")]).strip() if cmd.split()[0] in cmd_rpc.cmd_list:
cmd_rpc.call(cmd, host_list)
else:
print("您输入的命令暂不支持...")
continue
else:
break

RPC 指令分发器代码

RPC_executor指令执行器:

 #!/usr/bin/env python
# -*- coding:utf-8 -*-
__Author__ = "Zhang Xuyao" import pika
import os, time class RpcExecutor(object):
def __init__(self, rMQ_addr, ip):
self.connection = pika.BlockingConnection(pika.ConnectionParameters(
host=rMQ_addr))
self.channel = self.connection.channel() # 接收命令用
self.ip = ip
self.channel.exchange_declare(exchange='send', type='direct')
self.send_queue = self.channel.queue_declare()
self.send_queue_name = self.send_queue.method.queue
self.channel.queue_bind(exchange='send', routing_key=self.ip, queue=self.send_queue_name)
self.channel.basic_consume(self._on_request, queue=self.send_queue_name) # 开始订阅消息
def run(self):
print(" [x] Awaiting RPC requests")
self.channel.start_consuming() # 执行消息命令
def exec_cmd(self, cmd_str):
result = os.popen(cmd_str).read()
if not result:
return "命令没有输出结果"
else:
return result # 请求事件的回调函数
def _on_request(self, ch, method, props, body):
cmd_str = body.decode('utf-8')
print(" [.] exec_cmd(%s)" % cmd_str)
response = self.exec_cmd(cmd_str) # 发送命令结果,通过传来的queue进行发布,这里的app_id是额外增加的IP信息,区分于其他执行器的响应结果
ch.basic_publish(exchange='',
routing_key=props.reply_to,
properties=pika.BasicProperties(
correlation_id=props.correlation_id,
app_id=self.ip
),
body=str(response)
)
# 消息反馈确认,确保对方确实收到了响应结果
ch.basic_ack(delivery_tag=method.delivery_tag) def __del__(self):
self.connection.close() if __name__ == '__main__':
ip = input('请输入IP地址>>:')
cmd_executor = RpcExecutor('localhost', ip)
cmd_executor.run()

RPC 执行器代码

那些年被我坑过的Python——第十章Broker(rabbitMQ/redis)的更多相关文章

  1. Python之异步IO&RabbitMQ&Redis

    协程: 1.单线程运行,无法实现多线程. 2.修改数据时不需要加锁(单线程运行),子程序切换是线程内部的切换,耗时少. 3.一个cpu可支持上万协程,适合高并发处理. 4.无法利用多核资源,因为协程只 ...

  2. python命令行下安装redis客户端

    1. 安装文件: https://pypi.python.org/pypi/setuptools 直接下载然后拷贝到python目录下同下面步骤 下载 ez_setup.py>>> ...

  3. 廖雪峰js教程笔记6 generator一个坑 看完python在回来填坑

    generator(生成器)是ES6标准引入的新的数据类型.一个generator看上去像一个函数,但可以返回多次. ES6定义generator标准的哥们借鉴了Python的generator的概念 ...

  4. 那些年被我坑过的Python——邂逅与初识(第一章)

    第一问:为什么学习Python? 虚妖说:为了还债,还技术债,很早接触编程,却一直徘徊,也码了很多代码,却从未真真学会编程! 第二问:什么是Python 是一种以简洁.优雅著称的解释型.动态.强类型的 ...

  5. 那些年被我坑过的Python——一夫当关 第十三章(堡垒机初步设计)

      堡垒机架构 堡垒机的主要作用权限控制和用户行为审计,堡垒机就像一个城堡的大门,城堡里的所有建筑就是你不同的业务系统 , 每个想进入城堡的人都必须经过城堡大门并经过大门守卫的授权,每个进入城堡的人必 ...

  6. 那些年被我坑过的Python——牵一发动全身 第十一章MySQL、ORM

    #!/usr/bin/env python # -*- coding:utf-8 -*- __Author__ = "Zhang Xuyao" from sqlalchemy im ...

  7. 那些年被我坑过的Python——你来我往(第九章 selectors)

    进程.线程.协程(微线程).队列的概念理解 进程进程是所有相关资源的集合,而线程是和CPU交互的最小单元进程至少包含一个线程,是主线程线程线程之间可以共享资源线程同时修改同一份数据时必须加锁,mute ...

  8. 那些年被我坑过的Python——玄而又玄(第六章 面向对象编程基础)

    面向对象编程: 面向对象顾名思义,就是把组织代码的粒度从函数级别抽象到对象级别,对象是通过类来生成的,类可以想象为模板或进本框架而对象是在原有模板或框架的基础上增加详细信息的实体,类,有分类.聚类的含 ...

  9. 那些年被我坑过的Python——道阻且长(第五章实用模块讲解)

    random模块 我的随机验证吗程序: 首先保证了字母和数字出现的概率是50% VS 50%,其次是可以订制输出多少位 def Captcha(size): Captcha_list = [] for ...

随机推荐

  1. 青云QingCloud业内率先支持云端全面透明代理功能 | SDNLAB | 专注网络创新技术

    青云QingCloud业内率先支持云端全面透明代理功能 | SDNLAB | 专注网络创新技术 青云QingCloud业内率先支持云端全面透明代理功能

  2. UVa1151 Buy or Build

    填坑(p.358) 以前天真的以为用prim把n-1条边求出来就可以 现在看来是我想多了 #include<cstdio> #include<cstring> #include ...

  3. LINQ多条件OR模糊查询

    本文章转载:http://www.cnblogs.com/guyun/archive/2012/10/18/2729888.html 需求是这样的,有一张表tbl(Key[int],Value[str ...

  4. 屏蔽全部统计代码(51.la cnzz 百度统计 谷歌分析师adsense、屏蔽淘宝客广告代码)的方法

    支持百度统计 .51.la统计.cnzz统计.51yes统计.谷歌分析师.阿里妈妈淘宝客广告.chinaz弹窗.假设有很多其它的须要屏蔽的,欢迎联系 default7#zbphp.com 改动etc的 ...

  5. 栈的链式存储 - API实现

    基本概念 其它概念详情參看前一篇博文:栈的顺序存储 - 设计与实现 - API实现 这里也是运用了链表的链式存储API高速实现了栈的API. 代码: // linkstack.h // 链式存储栈的A ...

  6. Marquee滚动字幕设置(转)

    <marquee >滚动文字 </marquee> 方向 <direction=#> #=left, right,up,down 方式<bihavior=#& ...

  7. [转] Initial Impressions on GraphQL & Relay

    https://kadira.io/blog/graphql/initial-impression-on-relay-and-graphql http://graphql.org/blog/subsc ...

  8. android学习笔记----JNI中的c控制java

    面向对象的底层实现 java作为面向对象高级语言,可对现实世界进行建模.和面向过程不同的是面向对象软件的编写不是流程的堆积,而是对业务逻辑的多视角分解和分类.其过程大致为:      1).将知识分解 ...

  9. fedora虚拟机中的vsftp服务配置

    最近在学习unix,但在使用ftp链接虚拟机时总是总是各种报错,查了很多资料,试了很多方法,都有一定的问题,最后也算是久病成医,这里给其他跟我一样小白提供一个比较好的解决方案希望能有所帮助. Fedo ...

  10. Matlab使用xlsread, xlswrite函数导致excel进程无法终止的问题

    系统版本:Win7 64位 Matlab版本:R2015b 问题描述:使用excel的操作函数,比如xlsread,xlswrite,导致excel进程无法终止,任务管理器中仍残留excel进程,打开 ...