环境:windows或者Linux,python3.6,rabbitmq3.5
要求:
可以对指定机器异步的执行多个命令
例子:
>>:run "df -h" --hosts 192.168.3.55 10.4.3.4
task id: 45334
>>: check_task 45334
>>:
注意,每执行一条命令,即立刻生成一个任务ID,不需等待结果返回,通过命令check_task TASK_ID来得到任务结果 项目结构:
rpc_client ---|
bin ---|
start_client.py ......启动生成者
core---|
main.py ......生产者主程序
rpc_server ---|
bin ---|
start_server.py ......启动消费者
core---|
ftp_server.py ......消费者主程序 用法:
启动start_client.py,输入命令格式为 run "shell指令或者dos指令" --hosts ip ip
启动start_server.py
如果消费者本机ip为输入Ip之一,则回收到指令并返回指令结果
返回后打印task id
然后通过指令check_task id 则可以查询返回结果

producer:

#!/usr/bin/env python
# -*-coding:utf-8-*-
# Author:zh
import pika
import random class RpcClient(object):
# 这个类作为生成者,用来发消息
def __init__(self, command, ip, corr_id):
self.response = None # 消息
self.command = command # 命令
self.queue_name = ip # 管道名称为IP
self.corr_id = str(corr_id) # 随机生成的task id
self.connection = pika.BlockingConnection(pika.ConnectionParameters(host="localhost"))
self.channel = self.connection.channel()
self.channel.queue_declare(queue=self.queue_name, durable=True)
result = self.channel.queue_declare(exclusive=True)
self.callback_queue = result.method.queue
self.channel.basic_consume(self.on_response,
no_ack=True,
queue=self.callback_queue) def on_response(self, ch, method, props, body):
# 收到消息后根据corr_id判断消息是由谁返回
if self.corr_id == props.correlation_id:
self.response = body.decode() def call(self):
# 发送命令
self.channel.basic_publish(exchange='',
routing_key=self.queue_name,
properties=pika.BasicProperties(
reply_to=self.callback_queue,
correlation_id=self.corr_id,
delivery_mode=2,
),
body=self.command)
while self.response is None:
self.connection.process_data_events() # 非阻塞版的start_consume
return self.response class Command(object):
# 这个类用来解析命令并传给生产者
def __init__(self):
self.used_id = [] # 随机生成ID,避免重复,已生成的ID放入此列表中
self.id_data = {} # 将返回结果放入字典中存放 def run(self, *args):
# 这个方法用来解析命令并传给生产者
cmd = args[0]
cmd_str = cmd.split("\"")
try:
command = cmd_str[1]
ip_list = cmd_str[2].split()
ip_list.remove('--hosts')
corr_id = random.randint(10000, 99999)
while corr_id in self.used_id: # 防止corr_id重复
corr_id = random.randint(10000, 99999)
else:
self.used_id.append(corr_id)
return_body = {}
for i in ip_list:
rpc_obj = RpcClient(command, i, corr_id)
return_body[i] = rpc_obj.call()
self.id_data[corr_id] = return_body
print("task id:", corr_id)
except IndexError:
print("输入格式错误")
self.help()
except ValueError:
print("no --hosts")
self.help() def check_task(self, *args):
# 这个方法用来获取ID结果
cmd = args[0]
cmd_str = cmd.split()
if len(cmd_str) == 2:
corr_id = int(cmd_str[1])
if corr_id in list(self.id_data.keys()):
result = self.id_data.pop(corr_id)
for key in result:
print("\033[32;1m%s:\033[0m" % key)
for i in eval(result[key]):
print(i)
else:
print("no this task id") @staticmethod
def help():
print('''请输入以下命令格式:\033[32;1m
start command: run "command" --hosts ip ip get answer: check_task:id\033[0m
''') def start():
cmd_obj = Command()
while True:
cmd = input("-->:")
if len(cmd) == 0:
continue
cmd_str = cmd.split()
cmd_title = cmd_str[0]
if hasattr(cmd_obj, cmd_title):
func = getattr(cmd_obj, cmd_title)
func(cmd)
else:
cmd_obj.help()

main

consumer:

#!/usr/bin/env python
# -*-coding:utf-8-*-
# Author:zh
import pika
import subprocess
import locale
import codecs
import platform
import socket
import os class RpcServer(object):
# 这个类用来接收发来本机的消息,管道名为本机IP,将结果发往生成者
def __init__(self, queue_name):
self.connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
self.channel = self.connection.channel()
self.channel.queue_declare(queue=queue_name, durable=True)
self.channel.basic_consume(self.on_request, queue=queue_name) def start(self):
# 开始等待消息
self.channel.start_consuming() def on_request(self, ch, method, props, body):
# 收到消息后返回消息结果
response = self.run_order(body.decode())
ch.basic_publish(exchange='',
routing_key=props.reply_to,
properties=pika.BasicProperties(correlation_id=props.correlation_id,
delivery_mode=2,),
body=str(response))
ch.basic_ack(delivery_tag=method.delivery_tag) @staticmethod
def run_order(cmd):
# 这个方法用来执行命令并返回结果
cmd_result = subprocess.Popen(args=cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
return [
cmd_result.stdout.read().decode(codecs.lookup(locale.getpreferredencoding()).name),
cmd_result.stderr.read().decode(codecs.lookup(locale.getpreferredencoding()).name)
] if __name__ == "__main__":
hostname = socket.gethostname()
system_type = platform.system()
if system_type == 'Windows':
ip = socket.gethostbyname(hostname)
elif system_type == "Linux":
ip = str(os.popen("LANG=C ifconfig | grep \"inet addr\" | grep -v \"127.0.0.1\" | awk -F "
"\":\" '{print $2}' | awk '{print $1}'").readlines()[0]).strip() # 从Linux获取ip
prc_obj = RpcServer(ip)
prc_obj.start()

rabbitmq之rpc的更多相关文章

  1. RabbitMQ 实现RPC

    实现RPC 首先要弄明白,RPC是个什么东西. (RPC) Remote Procedure Call Protocol 远程过程调用协议 在一个大型的公司,系统由大大小小的服务构成,不同的团队维护不 ...

  2. RabbitMQ中RPC的实现及其通信机制

    RabbitMQ中RPC的实现:客户端发送请求消息,服务端回复响应消息,为了接受响应response,客户端需要发送一个回调队列的地址来接受响应,每条消息在发送的时候会带上一个唯一的correlati ...

  3. RabbitMQ(四):RPC的实现

    原文:RabbitMQ(四):RPC的实现 一.RPC RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议. ...

  4. 基于RabbitMQ的Rpc框架

    参考文档:https://www.cnblogs.com/ericli-ericli/p/5917018.html 参考文档:RabbitMQ 实现RPC MQ的使用场景大概包括解耦,提高峰值处理能力 ...

  5. RabbitMQ 笔记-RPC

    RabbitMQ中实现RPC的机制是: 客户端发送请求(消息)时,在消息的属性(MessageProperties,在AMQP协议中定义了14中properties,这些属性会随着消息一起发送)中设置 ...

  6. rabbitmq (五)RPC

    Remote Procedure Call or RPC(远程函数调用) 当我们需要在远程计算机上运行一个函数,并且等待结果的时候,我们用到RPC 在rabbitmq客户端使用call函数,发送RPC ...

  7. RabbitMQ、RPC、SaltStack "贡"具的使用

    消息队列 使用队列的场景 在程序系统中,例如外卖系统,订单系统,库存系统,优先级较高 发红包,发邮件,发短信,app消息推送等任务优先级很低,很适合交给消息队列去处理,以便于程序系统更快的处理其他请求 ...

  8. RabbitMQ除开RPC的五种消模型----原生API

    2.五种消息模型 RabbitMQ提供了6种消息模型,但是第6种其实是RPC,并不是MQ,因此不予学习.那么也就剩下5种. 但是其实3.4.5这三种都属于订阅模型,只不过进行路由的方式不同. 通过一个 ...

  9. Python通过RabbitMQ实现RPC

    Client端代码: #!/usr/bin/env python # -*- coding:utf-8 -*- import pika import uuid import time class Fi ...

随机推荐

  1. 【HHHOJ】ZJOI2019模拟赛(十四)03.12 解题报告

    点此进入比赛 得分: \(50+5+24=79\) 排名: \(Rank\ 2\) \(Rating\):\(+79\) \(T1\):[HHHOJ197]古明地(点此看题面) 基本上全部时间都用来想 ...

  2. 【洛谷P1996】约瑟夫问题

    约瑟夫问题 链表模拟大概是正解 #include<iostream> using namespace std; struct node{ //单链表 int d; node *next; ...

  3. rnn,lstm and JuergenSchmidhuber

    JuergenSchmidhuber 是瑞士的一位牛人,主要贡献是rnn, lstm. google的deep mind新作,Human-level control through deep rein ...

  4. JS isArray、typeof、instanceof

    Array.isArray() 用来检验是不是数组 var a = [1,2,3] console.log(typeof a); // object console.log(Array.isArray ...

  5. 深入理解JVM类加载机制

    1.什么是类加载机制? JVM把class文件加载到内存里面,并对数据进行验证.准备.解析和初始化,最终能够被形成被JVM可以直接使用的Java类型的过程. 生命周期包含:加载,验证,准备,解析,初始 ...

  6. JavaScript: window.onload = function() {} 里面的函数不执行

    问题:写了一个最简单的页面.在script标签中使用的 window.onload = function() { function add() { //... } } 页面上:<div oncl ...

  7. 关于 Angular引用Material出现node_modules/@angular/material/button-toggle/typings/button-toggle.d.ts(154,104): error TS2315: Type 'ElementRef' is not generic.问题

    百度了好久 ,,,最后谷歌出来了.. 该错误可能来自于您将@ angular / material设置为6.0.0, 但所有其他Angular包都是5.x.您应该始终确保Material主要版本与An ...

  8. 洛谷P1829 [国家集训队]Crash的数字表格 / JZPTAB(莫比乌斯反演)

    题目背景 提示:原 P1829 半数集问题 已经迁移至 P1028 数的计算 题目描述 今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数a ...

  9. PXE+DHCP+TFTP+Cobbler 无人值守安装centos 7

    Cobbler(补鞋匠)是通过将DHCP.TFTP.DNS.HTTP等服务进行集成,创建一个中央管理节点,其可以实现的功能有配置服务,创建存储库,解压缩操作系统媒介,代理或集成一个配置管理系统,控制电 ...

  10. list函数及list对象的reverse方法

    list的reverse方法,是就地reverse,不返回值 如a是一个list,a.reverse()直接将a这个list给reverse了,所以如果print(a.reverse())就是None ...