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 相关文章推荐
使用Pyrex来扩展和加速Python程序的教程
Apr 13 Python
python简单猜数游戏实例
Jul 09 Python
利用python批量检查网站的可用性
Sep 09 Python
Centos下实现安装Python3.6和Python2共存
Aug 15 Python
Python使用numpy产生正态分布随机数的向量或矩阵操作示例
Aug 22 Python
Python重新加载模块的实现方法
Oct 16 Python
Python3编码问题 Unicode utf-8 bytes互转方法
Oct 26 Python
python实现QQ邮箱/163邮箱的邮件发送
Jan 22 Python
python使用Paramiko模块实现远程文件拷贝
Apr 30 Python
Python+Selenium+phantomjs实现网页模拟登录和截图功能(windows环境)
Dec 11 Python
Python读写压缩文件的方法
Jul 30 Python
Python下opencv使用hough变换检测直线与圆
Jun 18 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
Win7 64位系统下PHP连接Oracle数据库
2014/08/20 PHP
8个PHP数组面试题
2015/06/23 PHP
PHP判断访客是否手机端(移动端浏览器)访问的方法总结【4种方法】
2019/03/27 PHP
让焦点自动跳转
2006/07/01 Javascript
Array.slice()与Array.splice()的返回值类型
2006/10/09 Javascript
javascript Window及document对象详细整理
2011/01/12 Javascript
JavaScript基础篇之变量作用域、传值、传址的简单介绍与实例
2013/06/29 Javascript
JavaScript中判断对象类型的几种方法总结
2013/11/11 Javascript
js 实现菜单左右滚动显示示例介绍
2013/11/21 Javascript
jQuery中parents()和parent()的区别分析
2014/10/28 Javascript
JavaScript中setUTCFullYear()方法的使用简介
2015/06/12 Javascript
JS实现可关闭的对联广告效果代码
2015/09/14 Javascript
javascript:void(0)是什么意思及href=#与href=javascriptvoid(0)的区别
2015/11/13 Javascript
onclick和onblur冲突问题的快速解决方法
2016/04/28 Javascript
Extjs4.0 ComboBox如何实现三级联动
2016/05/11 Javascript
jQuery Raty 一款不错的星级评分插件
2016/08/24 Javascript
javascript sort()对数组中的元素进行排序详解
2019/10/13 Javascript
JavaScript装饰者模式原理与用法实例详解
2020/03/09 Javascript
基于javascript的无缝滚动动画实现2
2020/08/07 Javascript
Python numpy 提取矩阵的某一行或某一列的实例
2018/04/03 Python
python实现图片文件批量重命名
2020/03/23 Python
详解Django中间件执行顺序
2018/07/16 Python
10个Python小技巧你值得拥有
2018/09/29 Python
python 队列基本定义与使用方法【初始化、赋值、判断等】
2019/10/24 Python
Python使用Tkinter实现滚动抽奖器效果
2020/01/06 Python
python爬虫开发之Request模块从安装到详细使用方法与实例全解
2020/03/09 Python
python报错TypeError: ‘NoneType‘ object is not subscriptable的解决方法
2020/11/05 Python
英国奢侈品网站:MatchesFashion
2016/12/16 全球购物
团队精神演讲稿
2013/12/31 职场文书
给医务人员表扬信
2014/01/12 职场文书
管理失职检讨书
2014/02/12 职场文书
洗发露广告词
2014/03/14 职场文书
优秀教师申报材料
2014/12/16 职场文书
聋哑人盗窃罪辩护词
2015/05/21 职场文书
听证会主持词
2015/07/03 职场文书
课题研究阶段性总结
2015/08/13 职场文书