rpc工作模式: 通过消息队列实现rpc功能, 客户端发送消息到消费队列, 服务端进行消费消息执行程序将结果再发送到回调队列, 供客户端使用. 是一种双向生产消费模式.
既是生产者又是消费者, 如果只有一个queue 则会出现死循环, 此时需要有一个回调队列.
客户端发消息时, 消息属性要设置上reply_to的回调队列, 把消息发送到指定的rpc队列, 通过process_data_events来保持连接并且检查是否有回调,
服务端从rpc队列里来确认客户端是否有发消息, 如果有则进行消费处理执行要做的事, 将处理的结果发送到客户端传来的回调队列里供客户端使用.
客户端传入数据, 服务端进行冒泡排序 再将结果返回给客户端.
结果展示
客户端demo
import pika
import uuid
import json
import random
class BubbleSortRpcClient(object):
def __init__(self):
self.username = 'sanford'
self.password = '123456'
self.host = 'localhost'
self.port = 5672
self.virtual_host = 'sanford_host'
credentials = pika.PlainCredentials(username=self.username, password=self.password)
params = pika.ConnectionParameters(host=self.host,
port=self.port,
virtual_host=self.virtual_host,
credentials=credentials)
# 创建连接
self.connection = pika.BlockingConnection(params)
# 创建信道
self.channel = self.connection.channel()
# 声明一个队列用于接收服务端返回结果, exclusive=True 只允许当前连接访问
result = self.channel.queue_declare(queue='', exclusive=True, durable=True)
self.callback_queue = result.method.queue
# 接收服务端返回的结果进行消费
self.channel.basic_consume(queue=self.callback_queue,
on_message_callback=self.on_response)
def on_response(self, ch, method, props, body):
"""
接收到服务端返回的结果的回调函数
"""
if self.corr_id == props.correlation_id:
if isinstance(body, str):
self.response = body
else:
self.response = json.loads(body)
ch.basic_ack(delivery_tag=method.delivery_tag)
def call(self, ls):
self.response = None
self.corr_id = str(uuid.uuid4())
# 请求消息属性设置 reply_to:接收服务端消息的队列
properties = pika.BasicProperties(delivery_mode=2,
reply_to=self.callback_queue,
correlation_id=self.corr_id)
# 发送请求消息
self.channel.basic_publish(exchange='',
routing_key='rpc_queue',
body=json.dumps(ls),
properties=properties)
while self.response is None:
# 保持连接 检查是否有回调
self.connection.process_data_events()
return self.response
if __name__ == '__main__':
bubble_sort = BubbleSortRpcClient()
ls_list = [
[1, 22, 3, 7, 4, 77, 34, 66, 5, 4, 8, 15],
'2223, 35, 44',
{2: 2, 3: 3},
[4, 7, 3, 9],
[3, 3, 9, 2]
]
idx = random.randint(0, 4)
print("客户端开始发起请求......")
response = bubble_sort.call(ls_list[idx])
print("服务端计算结果 response: {0}".format(response))
服务端demo
import pika
import json
class BubbleSortRpcService(object):
def __init__(self):
self.username = 'sanford'
self.password = '123456'
self.host = 'localhost'
self.port = 5672
self.virtual_host = 'sanford_host'
@staticmethod
def bubble_sort(ls):
"""
冒泡排序
"""
for i in range(len(ls) - 1):
for j in range(len(ls) - i - 1):
if ls[j] > ls[j + 1]:
ls[j], ls[j + 1] = ls[j + 1], ls[j]
return ls
def on_request(self, ch, method, props, body):
ls = json.loads(body)
print("客户端请求参数 ls:{0}".format(ls))
if isinstance(ls, list):
response = self.bubble_sort(ls)
else:
response = '客户端请求参数类型不对 type:{0}'.format(type(ls))
print("服务端计算结果 response:{0}".format(response))
# 服务端发送消息的属性设置
properties = pika.BasicProperties(delivery_mode=2,
correlation_id=props.correlation_id)
# 服务端发送计算后的结果, routing_key为客户端传来的reply_to
ch.basic_publish(exchange='',
routing_key=props.reply_to,
properties=properties,
body=json.dumps(response))
ch.basic_ack(delivery_tag=method.delivery_tag)
def run(self):
credentials = pika.PlainCredentials(username=self.username, password=self.password)
params = pika.ConnectionParameters(host=self.host,
port=self.port,
virtual_host=self.virtual_host,
credentials=credentials)
connection = pika.BlockingConnection(params)
channel = connection.channel()
channel.queue_declare(queue='rpc_queue', durable=True)
channel.basic_qos(prefetch_count=1)
channel.basic_consume(queue='rpc_queue', on_message_callback=self.on_request)
print("正在等待客户端请求......")
channel.start_consuming()
if __name__ == '__main__':
service = BubbleSortRpcService()
service.run()