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:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
c_handler:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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)
注意要点:1、c_client 发布消息到rabbitmq 需要携带 服务器返回的队列名称,及corr_id
2、c_handler 做了处理,每次发送的内容都会放到task列表中,直到显示ID号,就可以查询返回的内容,调用如下: