环境: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. 指定类型的成员XX”不支持实体LINQ。只有初始化,成员单位,和实体导航性能的支持。

    The specified type member 'DeleteFlag' is not supported in LINQ to Entities. Only initializers, enti ...

  2. poj 2115 扩展欧几里得

    题目链接:http://poj.org/problem?id=2115 题意: 给出一段循环程序,循环体变量初始值为 a,结束不等于 b ,步长为 c,看要循环多少次,其中运算限制在 k位:死循环输出 ...

  3. 打表格,字符串处理,POJ(2136)

    题目链接:http://poj.org/problem?id=2136 水题WA了半天,结果是数组开小了. #include <stdio.h> #include <string.h ...

  4. 课程设计__C++初步,C++对C的扩充

    小草的C++要结课了,小草终于翻起书来,小草用的老谭的书,有什么不对的就找老谭去吧. ///C++初步 ///C++对C的扩展 #include <iostream> using name ...

  5. rectified units

    from: http://en.wikipedia.org/wiki/Rectifier_(neural_networks) In the context of artificial neural n ...

  6. JAVA_Converter_字符串类型转Date类型

    我们知道数据库中的时间一般为Date类型,而前台传递过来的为字符串,BeanUtils在封装数据的时候,没有将类型转换,导致报异常... 我们只需要在封装数据之前,使用自定义转换器即可: 代码如下: ...

  7. 给大家一个我的QQ群

    很少关注博客了,提供一个QQ群讨论 我的一个QQ群:158351344

  8. web攻击技术与防护

    一.跨站脚本攻击(XSS) 跨站脚本攻击是指通过存在安全漏洞的Web网站注册用户的浏览器运行非法的HTML标签或JavaScript进行的一种攻击.动态创建的HTML部分有可能隐藏着安全漏洞.就这样, ...

  9. Struts2基础学习2

    Struts2基础学习2 项目结构,测试页面与实体类 <%@ page language="java" contentType="text/html; charse ...

  10. MySQL 5.7基于GTID的主从复制环境搭建(一主一从)

      Preface       As wel all know,replication base on GTID with row format of binary log is comprehens ...