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安装PIL模块时Unable to find vcvarsall.bat错误的解决方法
Sep 19 Python
Python使用openpyxl读写excel文件的方法
Jun 30 Python
分享一下如何编写高效且优雅的 Python 代码
Sep 07 Python
python 按照固定长度分割字符串的方法小结
Apr 30 Python
Python时间序列处理之ARIMA模型的使用讲解
Apr 02 Python
PyTorch的深度学习入门教程之构建神经网络
Jun 27 Python
python标记语句块使用方法总结
Aug 05 Python
python lambda函数及三个常用的高阶函数
Feb 05 Python
Windows系统下pycharm中的pip换源
Feb 23 Python
python GUI库图形界面开发之PyQt5滑块条控件QSlider详细使用方法与实例
Feb 28 Python
基于python实现把json数据转换成Excel表格
May 07 Python
python如何在word中存储本地图片
Apr 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
提取HTML标签
2006/10/09 PHP
php checkdate、getdate等日期时间函数操作详解
2010/03/11 PHP
PHP 数据结构 算法描述 冒泡排序 bubble sort
2011/07/10 PHP
Laravel 登录后清空COOKIE的操作方法
2019/10/14 PHP
BOOM vs RR BO5 第四场 2.14
2021/03/10 DOTA
ppk谈JavaScript style属性
2008/10/10 Javascript
仿迅雷焦点广告效果(JQuery版)
2008/11/19 Javascript
浅谈Javascript面向对象编程
2011/11/15 Javascript
node.js WEB开发中图片验证码的实现方法
2014/06/03 Javascript
node.js中的fs.statSync方法使用说明
2014/12/16 Javascript
JavaScript前端图片加载管理器imagepool使用详解
2014/12/29 Javascript
jQuery实现动态添加和删除一个div
2015/08/12 Javascript
jQuery Checkbox 全选 反选的简单实例
2016/11/29 Javascript
Bootstrap基本插件学习笔记之Alert警告框(20)
2016/12/08 Javascript
全选复选框JavaScript编写小结(附代码)
2017/08/16 Javascript
基于JavaScript实现一个简单的Vue
2018/09/26 Javascript
如何使用Node.js爬取任意网页资源并输出PDF文件到本地
2019/06/17 Javascript
微信小程序工具函数封装
2019/10/28 Javascript
详解小程序如何动态绑定点击的执行方法
2019/11/26 Javascript
jquery向后台提交数组的代码分析
2020/02/20 jQuery
微信小程序scroll-view的滚动条设置实现
2020/03/02 Javascript
python 爬取微信文章
2016/01/30 Python
PyQt5实现暗黑风格的计时器
2019/07/29 Python
Python MySQL 日期时间格式化作为参数的操作
2020/03/02 Python
Python中的__init__作用是什么
2020/06/09 Python
pandas数据处理之绘图的实现
2020/06/15 Python
python实现跨年表白神器--你值得拥有
2021/01/04 Python
纯css3制作网站后台管理面板
2014/12/30 HTML / CSS
举例详解HTML5中使用JSON格式提交表单
2015/06/16 HTML / CSS
爱尔兰电脑、家电和家具购物网站:Buy It Direct
2019/07/09 全球购物
全球异乡人的跨境社交电商平台:Kouhigh口嗨网
2020/07/24 全球购物
中间件分为哪几类
2012/03/14 面试题
物业管理求职自荐信
2013/09/25 职场文书
工商治理实习生的自我评价分享
2014/02/20 职场文书
高中班级口号
2014/06/09 职场文书
Spring Boot接口定义和全局异常统一处理
2022/04/20 Java/Android