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实现的Google IP 可用性检测脚本
Apr 23 Python
python实现合并两个数组的方法
May 16 Python
Python数据库的连接实现方法与注意事项
Feb 27 Python
python字符类型的一些方法小结
May 16 Python
python 采集中文乱码问题的完美解决方法
Sep 27 Python
如何利用Fabric自动化你的任务
Oct 20 Python
教你学会使用Python正则表达式
Sep 07 Python
Python AES加密实例解析
Jan 18 Python
python小项目之五子棋游戏
Dec 26 Python
Python线程条件变量Condition原理解析
Jan 20 Python
python中的对数log函数表示及用法
Dec 09 Python
Python编程中内置的NotImplemented类型的用法
Mar 23 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
从Web查询数据库之PHP与MySQL篇
2009/09/25 PHP
用javascript实现改变TEXTAREA滚动条和按钮的颜色,以及怎样让滚动条变得扁平
2007/04/20 Javascript
提高网站信任度的技巧
2008/10/17 Javascript
动态样式类封装JS代码
2009/09/02 Javascript
关于javascript function对象那些迷惑分析
2011/10/24 Javascript
jQuery的ready方法详解
2014/11/27 Javascript
javascript框架设计读书笔记之字符串的扩展和修复
2014/12/02 Javascript
node.js下when.js 的异步编程实践
2014/12/03 Javascript
JavaScript实现点击按钮切换网页背景色的方法
2015/10/17 Javascript
jQuery语法小结(超实用)
2015/12/31 Javascript
编写高质量JavaScript代码的基本要点
2016/03/02 Javascript
jQuery焦点图轮播插件KinSlideshow用法分析
2016/06/08 Javascript
JavaScript动态添加事件之事件委托
2016/07/12 Javascript
利用jQuery实现打字机字幕效果实例代码
2016/09/02 Javascript
jquery实现图片轮播器
2017/05/23 jQuery
使用ef6创建oracle数据库的实体模型遇到的问题及解决方案
2017/11/09 Javascript
vue初尝试--项目结构(推荐)
2018/01/30 Javascript
vue新建项目并配置标准路由过程解析
2019/12/09 Javascript
Python构造函数及解构函数介绍
2015/02/26 Python
简介二分查找算法与相关的Python实现示例
2015/08/26 Python
Python中使用Queue和Condition进行线程同步的方法
2016/01/19 Python
python3使用PyMysql连接mysql数据库实例
2017/02/07 Python
Python 实现的 Google 批量翻译功能
2019/08/26 Python
Python pandas.DataFrame 找出有空值的行
2019/09/09 Python
python logging 重复写日志问题解决办法详解
2020/08/04 Python
Falconeri美国官网:由羊绒和羊毛制成的针织服装
2018/04/08 全球购物
英国拖鞋购买网站:Bedroom Athletics
2020/02/28 全球购物
Napapijri西班牙在线商店:夹克、外套、运动衫等
2020/11/05 全球购物
网吧消防安全制度
2014/01/28 职场文书
公司门卫管理制度
2014/02/01 职场文书
各营销点岗位职责范本
2014/03/05 职场文书
2014银行领导班子四风对照检查材料思想汇报
2014/09/25 职场文书
死者家属慰问信
2015/03/24 职场文书
酒店销售经理岗位职责
2015/04/02 职场文书
运动会主持词大全
2015/07/02 职场文书
中学图书馆工作总结
2015/08/11 职场文书