Python RabbitMQ消息队列实现rpc


Posted in Python onMay 30, 2018

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

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

Python RabbitMQ消息队列实现rpc

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

c_server:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pika
import time
import json
import io
import yaml

s_exchange = input("请输入交换机名称->>").decode('utf-8').strip()
s_queue = input("输入消息队列名称->>").decode('utf-8').strip()
credentials = pika.PlainCredentials('system', 'manager')
connection = pika.BlockingConnection(pika.ConnectionParameters(host='XXX.XXX.XXX.XXX',credentials=credentials))
# 定义
channel = connection.channel()
channel.exchange_declare(exchange=s_exchange, exchange_type='direct')
channel.queue_declare(queue=s_queue, exclusive=True)
channel.queue_bind(queue=s_queue, exchange=s_exchange)

def s_manage(content):
 # 解决unicode转码问题 json.JSONDecoder().decode(content)
 str_content = yaml.safe_load(json.loads(content,encoding='utf-8'))
 str_res = {
  "errorid": 0,
  "resp": str_content['cmd'],
  "errorcont": "成功"
 }
 return json.dumps(str_res)

def on_request(ch, method, props, body):
 response = s_manage(body)
 ch.basic_publish(exchange='',
      routing_key=props.reply_to,
      properties=pika.BasicProperties(correlation_id = \
               props.correlation_id),
      body=response)
 ch.basic_ack(delivery_tag = method.delivery_tag)

channel.basic_qos(prefetch_count=1)
channel.basic_consume(on_request, queue=s_queue)

print(" [x] Awaiting RPC requests")
channel.start_consuming()

c_client:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import pika
import uuid
import json
import io

class RpcClient(object):
  def __init__(self):
    self.credentials = pika.PlainCredentials('guest', 'guest')
    self.connection = pika.BlockingConnection(pika.ConnectionParameters(host='XXX.XXX.XXX.XXX',
                                credentials=self.credentials))
    self.channel = self.connection.channel()

  def on_response(self, ch, method, props, body):
    if self.callback_id == props.correlation_id:
      self.response = body
    ch.basic_ack(delivery_tag=method.delivery_tag)

  def get_response(self, callback_queue, callback_id):
    '''取队列里的值,获取callback_queued的执行结果'''
    self.callback_id = callback_id
    self.response = None
    self.channel.queue_declare('q_manager', durable=True)
    self.channel.basic_consume(self.on_response, # 只要收到消息就执行on_response
                  queue=callback_queue)
    while self.response is None:
      self.connection.process_data_events() # 非阻塞版的start_consuming
    return self.response

  def call(self, queue_name, command, exchange,rout_key): # 命令下发
    '''队列里发送数据'''
    # result = self.channel.queue_declare(exclusive=False) #exclusive=False 必须这样写
    self.callback_queue = 'q_manager' # result.method.queue
    self.corr_id = str(uuid.uuid4())
    self.channel.basic_publish(exchange=exchange,
                  routing_key=queue_name,
                  properties=pika.BasicProperties(
                    reply_to=self.callback_queue, # 发送返回信息的队列name
                    correlation_id=self.corr_id, # 发送uuid 相当于验证码
                  ),
                  body=command)
    return self.callback_queue,self.corr_id

client

c_handler:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from c_client import *
import random, time
import threading
import json
import sys

class Handler(object):
  def __init__(self):
    self.information = {}  # 后台进程信息

  def check_all(self, *args):
    '''查看所有信息'''
    time.sleep(2)
    print('获取消息')
    for key in self.information:
      print("cid【%s】\t 队列【%s】\t 命令【%s】"%(key, self.information[key][0],
                               self.information[key][1]))

  def check_task(self, cmd):
    '''查看task_id执行结果'''
    time.sleep(2)
    try:
      task_id = int(cmd)
      print(task_id)
      callback_queue= self.information[task_id][2]
      callback_id= self.information[task_id][3]
      client = RpcClient()
      response = client.get_response(callback_queue, callback_id)
      print(response)
      # print(response.decode())
      del self.information[task_id]

    except KeyError as e :
      print("error: [%s]" % e)
    except IndexError as e:
      print("error: [%s]" % e)

  def run(self, user_cmd, host, exchange='', rout_key='',que=''):
    try:
      time.sleep(2)
      command = user_cmd
      task_id = random.randint(10000, 99999)
      client = RpcClient()
      response = client.call(queue_name=host, command=command,exchange=exchange,rout_key=que)
      self.information[task_id] = [host, command, response[0], response[1]]
    except IndexError as e:
      print("[error]:%s"%e)

  def reflect(self, str,cmd,host,exchange,que):
    '''反射'''
    if hasattr(self, str):
      getattr(self, str)(cmd,host,exchange,que)

  def start(self, m,cmd, host, exchange,que):
    while True:
      user_resp = input("输入处理消息内容ID->>").decode('utf-8').strip()
      self.check_task(user_resp)
      str = m
      print(self.information)
      t1 = threading.Thread(target=self.reflect, args=(str,cmd,host,exchange,que)) #多线程
      t1.start()

s_exchange = input("请输入交换机名称->>").decode('utf-8').strip()
s_queue = input("输入消息队列名称->>").decode('utf-8').strip()
d_cmd_state =input("输入json命令->>").decode('utf-8').strip()
s_cmd = json.dumps(d_cmd_state)
handler = Handler()
handler.start('run',s_cmd, s_queue, s_exchange, s_queue)

handler

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

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

Python RabbitMQ消息队列实现rpc

Python RabbitMQ消息队列实现rpc

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python复制文件代码实现
Dec 23 Python
python中判断文件编码的chardet(实例讲解)
Dec 21 Python
运动检测ViBe算法python实现代码
Jan 09 Python
Python学习笔记之open()函数打开文件路径报错问题
Apr 28 Python
对python中Matplotlib的坐标轴的坐标区间的设定实例讲解
May 25 Python
Python学习笔记之错误和异常及访问错误消息详解
Aug 08 Python
10分钟教你用python动画演示深度优先算法搜寻逃出迷宫的路径
Aug 12 Python
Python 单例设计模式用法实例分析
Sep 23 Python
pycharm的python_stubs问题
Apr 08 Python
什么是Python中的顺序表
Jun 02 Python
python爬虫可以爬什么
Jun 16 Python
Pytorch distributed 多卡并行载入模型操作
Jun 05 Python
python日期时间转为字符串或者格式化输出的实例
May 29 #Python
python 集合 并集、交集 Series list set 转换的实例
May 29 #Python
使用Django启动命令行及执行脚本的方法
May 29 #Python
python3中的md5加密实例
May 29 #Python
python 获取字符串MD5值方法
May 29 #Python
Python生成短uuid的方法实例详解
May 29 #Python
Python(TensorFlow框架)实现手写数字识别系统的方法
May 29 #Python
You might like
PHP+MYSQL开发工具及资源收藏
2007/01/02 PHP
php mysql_list_dbs()函数用法示例
2017/03/29 PHP
jquery的Theme和Theme Switcher使用小结
2010/09/08 Javascript
JQuery中根据属性或属性值获得元素(6种情况获取方法)
2013/01/17 Javascript
获取非最后一列td值并将title设为该值的方法
2013/10/30 Javascript
老生常谈Javascript中的原型和this指针
2016/10/09 Javascript
JS动态给对象添加属性和值的实现方法
2016/10/21 Javascript
Bootstrap基本样式学习笔记之按钮(4)
2016/12/07 Javascript
ReactNative Image组件使用详解
2017/08/07 Javascript
在 Angular6 中使用 HTTP 请求服务端数据的步骤详解
2018/08/06 Javascript
Vue起步(无cli)的啊教程详解
2019/04/11 Javascript
浅析我对JS延迟异步脚本的思考
2020/10/12 Javascript
[02:11]2016国际邀请赛中国区预选赛最美TA采访现场玩家
2016/06/28 DOTA
Python中的列表知识点汇总
2015/04/14 Python
安装dbus-python的简要教程
2015/05/05 Python
Python利用Beautiful Soup模块创建对象详解
2017/03/27 Python
Python使用matplotlib绘制正弦和余弦曲线的方法示例
2018/01/06 Python
Python中将dataframe转换为字典的实例
2018/04/13 Python
python的pytest框架之命令行参数详解(上)
2019/06/27 Python
Python基础之高级变量类型实例详解
2020/01/03 Python
使用PyTorch将文件夹下的图片分为训练集和验证集实例
2020/01/08 Python
pandas.DataFrame.drop_duplicates 用法介绍
2020/07/06 Python
Python读取yaml文件的详细教程
2020/07/21 Python
详解CSS3开启硬件加速的使用和坑
2017/08/21 HTML / CSS
HTML5操作WebSQL数据库的实例代码
2017/08/26 HTML / CSS
Omio俄罗斯:一次搜索公共汽车、火车和飞机的机票
2018/11/17 全球购物
美国美食礼品篮网站:Gourmet Gift Baskets
2019/12/15 全球购物
某公司C#程序员面试题笔试题
2014/05/26 面试题
建筑工程技术应届生求职信
2013/11/17 职场文书
2014全国两会学习心得体会2000字
2014/03/10 职场文书
初中学习计划书范文
2014/09/15 职场文书
白鹤梁导游词
2015/02/06 职场文书
电子商务专业求职信范文
2015/03/19 职场文书
横空出世观后感
2015/06/09 职场文书
Python Django获取URL中的数据详解
2021/11/01 Python
配置nginx负载均衡
2022/05/06 Servers