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检测手机QQ在线状态的脚本代码
Feb 10 Python
在Mac OS上使用mod_wsgi连接Python与Apache服务器
Dec 24 Python
浅谈python中的正则表达式(re模块)
Oct 17 Python
python 实现一次性在文件中写入多行的方法
Jan 28 Python
python对象与json相互转换的方法
May 07 Python
python实现简单聊天室功能 可以私聊
Jul 12 Python
Django app配置多个数据库代码实例
Dec 17 Python
使用Django和Postgres进行全文搜索的实例代码
Feb 13 Python
Python读入mnist二进制图像文件并显示实例
Apr 24 Python
基于python实现获取网页图片过程解析
May 11 Python
在pytorch中动态调整优化器的学习率方式
Jun 24 Python
python3.7.2 tkinter entry框限定输入数字的操作
May 22 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读注册表
2006/10/09 PHP
thinkPHP实现MemCache分布式缓存功能
2016/03/23 PHP
laravel 多图上传及图片的存储例子
2019/10/14 PHP
jquery使用jquery.zclip插件复制对象的实例教程
2013/12/04 Javascript
点击按钮自动加关注的代码(sina微博/QQ空间/人人网/腾讯微博)
2014/01/02 Javascript
实现图片预加载的三大方法及优缺点分析
2014/11/19 Javascript
jQuery实现鼠标滚轮动态改变样式或效果
2015/01/05 Javascript
jquery通过扩展select控件实现支持enter或focus选择的方法
2015/11/19 Javascript
js图片跟随鼠标移动代码
2015/11/26 Javascript
JavaScript实现页面跳转的方式汇总
2016/05/16 Javascript
jQuery实现可移动选项的左右下拉列表示例
2016/12/26 Javascript
AngularJS中的promise用法分析
2017/05/19 Javascript
Vue 2.5 Level E 发布了: 新功能特性一览
2017/10/24 Javascript
vue.js绑定事件监听器示例【基于v-on事件绑定】
2018/07/07 Javascript
微信小程序Page中data数据操作和函数调用方法
2019/05/08 Javascript
怎样在vue项目下添加ESLint的方法
2019/05/16 Javascript
vue 路由懒加载中给 Webpack Chunks 命名的方法
2020/04/24 Javascript
Python中多线程thread与threading的实现方法
2014/08/18 Python
Python制作爬虫采集小说
2015/10/25 Python
Python实现的绘制三维双螺旋线图形功能示例
2018/06/23 Python
python实现键盘输入的实操方法
2019/07/16 Python
Python中低维数组填充高维数组的实现
2019/12/02 Python
pycharm 更改创建文件默认路径的操作
2020/02/15 Python
基于python实现模拟数据结构模型
2020/06/12 Python
Python Merge函数原理及用法解析
2020/09/16 Python
CSS3实现王者荣耀匹配人员加载页面的方法
2019/04/16 HTML / CSS
课前一分钟演讲稿
2014/08/26 职场文书
简易离婚协议书范本2014
2014/10/15 职场文书
计算机实训报告总结
2014/11/05 职场文书
五四青年节比赛演讲稿
2015/03/18 职场文书
2015秋季新学期开学寄语
2015/05/28 职场文书
党员发展大会主持词
2015/07/03 职场文书
三八红旗手主要事迹材料
2015/11/04 职场文书
《平行四边形的面积》教学反思
2016/02/16 职场文书
《家庭教育》读后感3篇
2019/12/18 职场文书
详解SQL报错盲注
2022/07/23 SQL Server