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天气预报采集器实现代码(网页爬虫)
Oct 07 Python
python 计算文件的md5值实例
Jan 13 Python
Python编程实现的简单Web服务器示例
Jun 22 Python
Python3使用正则表达式爬取内涵段子示例
Apr 22 Python
python实现下载pop3邮件保存到本地
Jun 19 Python
Python3.6实现带有简单界面的有道翻译小程序
Apr 16 Python
pyqt5 获取显示器的分辨率的方法
Jun 18 Python
python获取指定日期范围内的每一天,每个月,每季度的方法
Aug 08 Python
Matplotlib使用字符串代替变量绘制散点图的方法
Feb 17 Python
Python新手学习标准库模块命名
May 29 Python
python两个list[]相加的实现方法
Sep 23 Python
Python MNIST手写体识别详解与试练
Nov 07 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写的留言本
2006/10/09 PHP
php中删除字符串中最先出现某个字符的实现代码
2013/02/03 PHP
PHP操作MongoDB GridFS 存储文件的详解
2013/06/20 PHP
关于PHP自动判断字符集并转码的详解
2013/06/26 PHP
php模拟ping命令(php exec函数的使用方法)
2013/10/25 PHP
在Ubuntu 14.04上部署 PHP 环境及 WordPress
2014/09/02 PHP
php过滤表单提交的html等危险代码
2014/11/03 PHP
PHP中STDCLASS用法实例分析
2016/11/11 PHP
jquery mobile事件多次绑定示例代码
2013/09/13 Javascript
JQuery 在线引用及测试引用是否成功
2014/06/24 Javascript
Bootstrap中的Panel和Table全面解析
2016/06/13 Javascript
js跨域资源共享 基础篇
2016/07/02 Javascript
JS文件上传神器bootstrap fileinput详解
2021/01/28 Javascript
TypeScript入门-接口
2017/03/30 Javascript
vue.js父组件使用外部对象的方法示例
2017/04/25 Javascript
JavaScript的继承实现小结
2017/05/07 Javascript
jquery.validate表单验证插件使用详解
2017/06/21 jQuery
JS+HTML实现的圆形可点击区域示例【3种方法】
2018/08/01 Javascript
vue实现倒计时获取验证码效果
2020/04/17 Javascript
Python中的异常处理学习笔记
2015/01/28 Python
Python运算符重载用法实例分析
2015/06/01 Python
python中装饰器级连的使用方法示例
2017/09/29 Python
查看python下OpenCV版本的方法
2018/08/03 Python
python判断文件夹内是否存在指定后缀文件的实例
2019/06/10 Python
装上这 14 个插件后,PyCharm 真的是无敌的存在
2021/01/11 Python
虚拟环境及venv和virtualenv的区别说明
2021/02/05 Python
python推导式的使用方法实例
2021/02/28 Python
惠普香港官方商店:HP香港
2019/04/30 全球购物
经济担保书范文
2014/04/02 职场文书
党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
销售内勤岗位职责范本
2015/04/13 职场文书
2016年元旦寄语
2015/08/17 职场文书
《棉鞋里的阳光》教学反思
2016/02/20 职场文书
python - asyncio异步编程
2021/04/06 Python
WebWorker 封装 JavaScript 沙箱详情
2021/11/02 Javascript
天谕手游15杯全调酒配方和调酒券的获得方式
2022/04/06 其他游戏