代码改变世界

python 之rabbitmq rpc

2018-05-29 17:29  dugufei  阅读(267)  评论(0编辑  收藏  举报

 

  上个项目中用到了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号,就可以查询返回的内容,调用如下: