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使用PythonMagick将jpg图片转换成ico图片的方法
Mar 26 Python
使用Python脚本对Linux服务器进行监控的教程
Apr 02 Python
浅析Python编写函数装饰器
Mar 18 Python
python使用turtle库绘制时钟
Mar 25 Python
python 读取视频,处理后,实时计算帧数fps的方法
Jul 10 Python
Python GUI编程 文本弹窗的实例
Jun 11 Python
Python参数类型以及常见的坑详解
Jul 08 Python
python自动识别文本编码格式代码
Dec 26 Python
Python常用库大全及简要说明
Jan 17 Python
Keras SGD 随机梯度下降优化器参数设置方式
Jun 19 Python
利用Vscode进行Python开发环境配置的步骤
Jun 22 Python
jupyter notebook指定启动目录的方法
Mar 02 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
56.com视频采集接口程序(PHP)
2007/09/22 PHP
PHP mkdir()定义和用法
2009/01/14 PHP
延长phpmyadmin登录时间的方法
2011/02/06 PHP
完美解决:Apache启动问题―(OS 10022)提供了一个无效的参数
2013/06/08 PHP
PHP微框架Dispatch简介
2014/06/12 PHP
Centos6.5和Centos7 php环境搭建方法
2016/05/27 PHP
CI框架(CodeIgniter)实现的数据库增删改查操作总结
2018/05/23 PHP
PHP生成zip压缩包的常用方法示例
2019/08/22 PHP
JavaScript面向对象之静态与非静态类
2010/02/03 Javascript
JS控制显示隐藏兼容问题(IE6、IE7、IE8)
2010/04/01 Javascript
javascript中常用编程知识
2013/04/08 Javascript
js判断手机访问或者PC的几个例子(常用于手机跳转)
2015/12/15 Javascript
JS判断是否在微信浏览器打开的简单实例(推荐)
2016/08/24 Javascript
AngularJS 支付倒计时功能实现思路
2017/06/05 Javascript
微信小程序--获取用户地理位置名称(无须用户授权)的方法
2019/04/29 Javascript
微信小程序系列之自定义顶部导航功能
2019/05/21 Javascript
详解Vue的七种传值方式
2021/02/08 Vue.js
python批量制作雷达图的实现方法
2016/07/26 Python
Django实现简单分页功能的方法详解
2017/12/05 Python
利用Python将文本中的中英文分离方法
2018/10/31 Python
Pytorch基本变量类型FloatTensor与Variable用法
2020/01/08 Python
基于python检查SSL证书到期情况代码实例
2020/04/04 Python
解决matplotlib.pyplot在Jupyter notebook中不显示图像问题
2020/04/22 Python
Pythonic版二分查找实现过程原理解析
2020/08/11 Python
台湾乐天市场:日本No.1的网路购物网站
2017/03/22 全球购物
一名女生的自荐信
2013/12/08 职场文书
打架检讨书400字
2014/01/17 职场文书
高中生的自我鉴定范文
2014/01/24 职场文书
群众路线教育实践活动心得体会
2014/03/07 职场文书
小学教师读书活动总结
2014/07/08 职场文书
文明单位创建材料
2014/12/24 职场文书
2015年安全月活动总结
2015/03/26 职场文书
2015年留守儿童工作总结
2015/05/22 职场文书
婚庆答谢词大全
2015/09/29 职场文书
mysql死锁和分库分表问题详解
2021/04/16 MySQL
Python函数式编程中itertools模块详解
2021/09/15 Python