首先先上一个rabbitmq的工作示意图,这种情况是rabbitmq最简单的一种通信,之后有时间会上多exchange之间的消息交互的文章,也欢迎大家一起学习,一起讨论。
import uuid
from time import time, sleep
import traceback
import pika
import threading
class Rpc_cilent(object):
_queue = {}
_internal_lock = threading.RLock()
def __init__(self, id, host="127.0.0.1", port=5672, username="guest", password="guest", v_host="/"):
'''交换机,可认为是网络交换机,只要连接在同一个交换机上的队列都可以进行通信'''
self._exchange_name = "wu_queue"
self._callback_queue_name = "rpc_client_{}".format(id) # 当前客户端与交换机连接的队列
self._routing_key = "server_rpc_{}".format(id) # 当前客户端的地址(唯一标识)
self._broker_url = "amqp://{}:{}@{}:{}{}".format(username, password, host, port, v_host)
self._param = pika.URLParameters(self._broker_url)
self._thread = threading.Thread(target=self._run)
self._thread.setDaemon(False)
self._thread.start()
def _run(self):
print("已运行")
try:
self.__connect()
self.__process_data_event()
except Exception as e:
sleep(5)
print("_run connection exception : {}".format(traceback.format_exc()))
def __connect(self):
# 创建rabbitmq连接对象
self._connection = pika.BlockingConnection(parameters=self._param)
# print("创建rabbitmq对象")
# 创建信道
self._channel = self._connection.channel()
# 声明或创建交换机
# exchange:交换机的名称
# exchange_type:交换机的类型
# durbale:队列是否持久化
# auto_delete:连接断开时,是否自动删除exchange
self._channel.exchange_declare(exchange=self._exchange_name, exchange_type="topic", durable=True,
auto_delete=False)
# 声明创建队列
# queue:列队名称
# exclusive:是否排外,True的话,当队列关闭后会自动删除,一个列队只能有一个消费者去消费
self._channel.queue_declare(queue=self._callback_queue_name, exclusive=False, auto_delete=True)
# 将列队和交换机通过routing_key绑定
self._channel.queue_bind(queue=self._callback_queue_name, exchange=self._exchange_name,
routing_key=self._routing_key)
def __process_data_event(self):
# no_ack:开启自动确认,否则处理后的消息会一直留在队列中
self._channel.basic_consume(self.__on_response, no_ack=True, queue=self._callback_queue_name)
while True:
'''以下方法是阻塞式的监听列队收到的消息,若有消息则去消费'''
with self._internal_lock:
self._connection.process_data_events()
sleep(0.1)
'''接收返回信息的接口,参数是固定的,将接收的信息存入到字典中'''
def __on_response(self, ch, method, props, body):
self._queue[props.correlation_id] = body
print("收到的返回消息为:", body)
def __send_message(self, toAddress, body_msg, notify=False):
# 生成消息的id(唯一标识)
correlation_id = str(uuid.uuid4())
props = pika.BasicProperties(content_type="application/json")
if not notify:
self._queue[correlation_id] = None
props.reply_to = self._routing_key # 指定回调地址
props.correlation_id = correlation_id # 指定发送消息的id
with self._internal_lock:
# 发送消息
self._channel.basic_publish(exchange=self._exchange_name,
routing_key="worker.{}".format(toAddress),
properties=props,
body=str(body_msg))
print("发送消息成功!")
return correlation_id
def call(self, toAddress, message, timeout=10.0, notify=False):
'''
调用发送接口,并获取返回结果
:param toAddress: 消息发送地址
:param message: 发送的消息
:param timeout: 等待返回的超时时间
:param notify: 是否等待返回消息标识符
:return: 返回结果
'''
def current_millmi_time():
return int(time())
# toAddress,message 必须为字符串类型
for p in (toAddress, message):
if not (isinstance(p, str)):
raise TypeError
begin = current_millmi_time()
body = {"msg": message}
print("body: ", body)
correlation_id = self.__send_message(toAddress, body, notify)
print("corr_id: ", correlation_id)
if notify:
'''仅发送消息,无需等待返回消息'''
return True
# 判断消息是否返回,做超时处理
while self._queue[correlation_id] is None:
if current_millmi_time() - begin > int(timeout):
raise RuntimeError
print("返回值为:", self._queue[correlation_id])
return self._queue.pop(correlation_id)
if __name__ == '__main__':
rpc_client = Rpc_cilent("wu”)
from time import time, sleep
import traceback
import pika
import threading
class Rpc_worker(object):
_queue = {}
_internal_lock = threading.RLock()
def __init__(self, id, host="127.0.0.1", port=5672, username="guest", password="guest", v_host="/"):
self._exchange_name = "wu_queue"
self._callback_queue_name = "rpc_worker_{}".format(id) #定义该客户端与交换机交互的队列
self._routing_key = "worker.{}".format(id) #该客户端的地址(唯一标识)
self._broker_url = "amqp://{}:{}@{}:{}{}".format(username, password, host, port, v_host)
self._param = pika.URLParameters(self._broker_url)
self._thread = threading.Thread(target=self._run)
self._thread.setDaemon(False)
self._thread.start()
def _run(self):
print("已运行")
# while True:
try:
self.__connect()
'''监听队列的方法必须开启子线程执行,否则会阻塞主线程'''
self.__process_data_event()
except Exception as e:
print("_run connection exception : {}".format(traceback.format_exc()))
sleep(5)
def __connect(self):
# 创建rabbitmq连接对象
self._connection = pika.BlockingConnection(parameters=self._param)
# print("创建rabbitmq对象")
# 创建信道
self._channel = self._connection.channel()
# 声明或创建交换机
# exchange:交换机的名称
# exchange_type:交换机的类型
# durbale:队列是否持久化
# auto_delete:连接断开时,是否自动删除exchange
self._channel.exchange_declare(exchange=self._exchange_name, exchange_type="topic", durable=True,
auto_delete=False)
# 声明创建队列
# queue:列队名称
# exclusive:是否排外,True的话,当队列关闭后会自动删除,一个列队只能有一个消费者去消费
self._channel.queue_declare(queue=self._callback_queue_name, exclusive=False, auto_delete=True)
# 将列队和交换机通过routing_key绑定
self._channel.queue_bind(queue=self._callback_queue_name, exchange=self._exchange_name,
routing_key=self._routing_key)
def __process_data_event(self):
# no_ack:开启自动确认,否则处理后的消息会一直留在队列中
self._channel.basic_consume(self.__on_response, no_ack=True, queue=self._callback_queue_name)
while True:
with self._internal_lock:
'''以下方法是阻塞式的监听列队收到的消息,若有消息则去消费'''
self._connection.process_data_events()
sleep(0.1)
#接收信息的接口,参数不可变
def __on_response(self, ch, method, props, body):
self._queue[props.correlation_id] = body
print("收到的返回消息为:", body)
response = "worker incept message,thanks!!!"
self.__send_message(props, response)
print("reply_to: %s" % props.reply_to)
def __send_message(self, props, response):
properties = pika.BasicProperties(content_type="application/json",
correlation_id=props.correlation_id) # 消息的唯一标识
with self._internal_lock:
# 发送消息
self._channel.basic_publish(self._exchange_name,
props.reply_to, # 目的地的地址
properties=properties,
body=str(response))
print("消息已发送!")
if __name__ == '__main__':
rpc_client = Rpc_worker("wu”)
import time
from emit_log_topic import rpc_client as rpc #emit_log_topic:客户端client1(发送端)的代码脚本名
n=1
while True:
try:
id=rpc.call("wu","hello rabbitmq %s" % n)
print("corr_id: ",id)
time.sleep(2)
print("发送次数:",n)
n+=1
except Exception as e:
print("error: ",e)
1.首先安装rabbitmq服务,针对不同的系统去网上搜索相应的安装教程
2.启动rebbitmq服务,通过web页面访问rabbitmq控制台
3.将以上代码执行,先启动客户端client1和客户端client2的服务
4.再执行消息发送命令