python 之rabbitmq rpc

  上个项目中用到了ActiveMQ,只是简单应用,安装完成后直接是用就可以了。由于新项目中一些硬件的限制,需要把消息队列换成RabbitMQ。

RabbitMQ中的几种模式和机制比ActiveMQ多多了,根据业务需要,使用RPC实现功能,其中踩过的一些坑,有必要记录一下了。

        上代码,目录结构分为 c_server、c_client、c_hanlder:

         c_server:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-  3 import pika  4 import time  5 import json  6 import io  7 import yaml  8  9 s_exchange = input("请输入交换机名称->>").decode('utf-8').strip() 10 s_queue = input("输入消息队列名称->>").decode('utf-8').strip() 11 credentials = pika.PlainCredentials('system', 'manager') 12 connection = pika.BlockingConnection(pika.ConnectionParameters(host='XXX.XXX.XXX.XXX',credentials=credentials))
13 # 定义 14 channel = connection.channel() 15 channel.exchange_declare(exchange=s_exchange, exchange_type='direct') 16 channel.queue_declare(queue=s_queue, exclusive=True) 17 channel.queue_bind(queue=s_queue, exchange=s_exchange) 18 19 def s_manage(content): 20 # 解决unicode转码问题 json.JSONDecoder().decode(content) 21 str_content = yaml.safe_load(json.loads(content,encoding='utf-8')) 22 str_res = { 23 "errorid": 0, 24 "resp": str_content['cmd'], 25 "errorcont": "成功" 26 } 27 return json.dumps(str_res) 28 29 def on_request(ch, method, props, body): 30 response = s_manage(body) 31 ch.basic_publish(exchange='', 32 routing_key=props.reply_to, 33 properties=pika.BasicProperties(correlation_id = \ 34 props.correlation_id), 35 body=response) 36 ch.basic_ack(delivery_tag = method.delivery_tag) 37 38 channel.basic_qos(prefetch_count=1) 39 channel.basic_consume(on_request, queue=s_queue) 40 41 print(" [x] Awaiting RPC requests") 42 channel.start_consuming()

 c_client:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-  3  4 import pika  5 import uuid  6 import json  7 import io  8  9 class RpcClient(object): 10 def __init__(self): 11 self.credentials = pika.PlainCredentials('guest', 'guest') 12 self.connection = pika.BlockingConnection(pika.ConnectionParameters(host='XXX.XXX.XXX.XXX', 13 credentials=self.credentials)) 14 self.channel = self.connection.channel() 15 16 def on_response(self, ch, method, props, body): 17 if self.callback_id == props.correlation_id: 18 self.response = body 19 ch.basic_ack(delivery_tag=method.delivery_tag) 20 21 def get_response(self, callback_queue, callback_id): 22 '''取队列里的值,获取callback_queued的执行结果''' 23 self.callback_id = callback_id 24 self.response = None 25 self.channel.queue_declare('q_manager', durable=True) 26 self.channel.basic_consume(self.on_response, # 只要收到消息就执行on_response 27 queue=callback_queue) 28 while self.response is None: 29 self.connection.process_data_events() # 非阻塞版的start_consuming 30 return self.response 31 32 def call(self, queue_name, command, exchange,rout_key): # 命令下发 33 '''队列里发送数据''' 34 # result = self.channel.queue_declare(exclusive=False) #exclusive=False 必须这样写 35 self.callback_queue = 'q_manager' # result.method.queue 36 self.corr_id = str(uuid.uuid4()) 37 self.channel.basic_publish(exchange=exchange, 38 routing_key=queue_name, 39 properties=pika.BasicProperties( 40 reply_to=self.callback_queue, # 发送返回信息的队列name 41 correlation_id=self.corr_id, # 发送uuid 相当于验证码 42  ), 43 body=command) 44 return self.callback_queue,self.corr_id
client

c_handler:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-  3  4 from c_client import *  5 import random, time  6 import threading  7 import json  8 import sys  9 10 class Handler(object): 11 def __init__(self): 12 self.information = {} # 后台进程信息 13 14 def check_all(self, *args): 15 '''查看所有信息''' 16 time.sleep(2) 17 print('获取消息') 18 for key in self.information: 19 print("cid【%s】\t 队列【%s】\t 命令【%s】"%(key, self.information[key][0], 20 self.information[key][1])) 21 22 def check_task(self, cmd): 23 '''查看task_id执行结果''' 24 time.sleep(2) 25 try: 26 task_id = int(cmd) 27 print(task_id) 28 callback_queue= self.information[task_id][2] 29 callback_id= self.information[task_id][3] 30 client = RpcClient() 31 response = client.get_response(callback_queue, callback_id) 32 print(response) 33 # print(response.decode()) 34 del self.information[task_id] 35 36 except KeyError as e : 37 print("error: [%s]" % e) 38 except IndexError as e: 39 print("error: [%s]" % e) 40 41 def run(self, user_cmd, host, exchange='', rout_key='',que=''): 42 try: 43 time.sleep(2) 44 command = user_cmd 45 task_id = random.randint(10000, 99999) 46 client = RpcClient() 47 response = client.call(queue_name=host, command=command,exchange=exchange,rout_key=que) 48 self.information[task_id] = [host, command, response[0], response[1]] 49 except IndexError as e: 50 print("[error]:%s"%e) 51 52 def reflect(self, str,cmd,host,exchange,que): 53 '''反射''' 54 if hasattr(self, str): 55  getattr(self, str)(cmd,host,exchange,que) 56 57 def start(self, m,cmd, host, exchange,que): 58 while True: 59 user_resp = input("输入处理消息内容ID->>").decode('utf-8').strip() 60  self.check_task(user_resp) 61 str = m 62 print(self.information) 63 t1 = threading.Thread(target=self.reflect, args=(str,cmd,host,exchange,que)) #多线程 64  t1.start() 65 66 s_exchange = input("请输入交换机名称->>").decode('utf-8').strip() 67 s_queue = input("输入消息队列名称->>").decode('utf-8').strip() 68 d_cmd_state =input("输入json命令->>").decode('utf-8').strip() 69 s_cmd = json.dumps(d_cmd_state) 70 handler = Handler() 71 handler.start('run',s_cmd, s_queue, s_exchange, s_queue)
handler

注意要点:1、c_client 发布消息到rabbitmq 需要携带 服务器返回的队列名称,及corr_id

      2、c_handler 做了处理,每次发送的内容都会放到task列表中,直到显示ID号,就可以查询返回的内容,调用如下:

                

       

猜你喜欢

转载自www.cnblogs.com/dugufei/p/9105581.html