day11-rabbit MQ rpc remote procedure call

一、前言

  转载师兄博客

  之前我们都是单向发送消息,客户端发送消息给服务端,那么问题来了,我现在发一个命令给远程客户端,让它去执行,执行之后的结果,我想把这个结果再返回。这个模型叫什么呐,这种模型叫RPC=>remote procedure call。

  怎么返回这个消息呢?

  答:就server 端和客户端既是消费者,又是生产者。

  想要深入了解RabbitMQ:猛击这里

二、模型图

三、逻辑代码

3.1、RPC Client

 

 1 import pika,uuid,time
 2 
 3 class FibonacciRpcClient(object):
 4     "斐波那契数列rpc客户端"
 5 
 6     def __init__(self):
 7         self.connection = pika.BlockingConnection(pika.ConnectionParameters
 8                                                   (host="localhost"))
 9         self.channel = self.connection.channel()
10         result = self.channel.queue_declare(exclusive=True)
11         self.callback_queue = result.method.queue
12         self.channel.basic_consume(self.on_response,no_ack=True,
13                                    queue=self.callback_queue)
14 
15     def on_response(self,ch,method,props,body):
16         print("---->",method,props)
17         if self.corr_id == props.correlation_id: #我发过去的结果就是我想要的结果,保持数据的一致性
18             self.response = body
19 
20 
21     def call(self,n):
22         self.response = None
23         self.corr_id = str(uuid.uuid4())
24         self.channel.publish(exchange="",
25                              routing_key="rpc_queue",
26                              properties=pika.BasicProperties(
27                                  reply_to=self.callback_queue,
28                                  correlation_id=self.corr_id),
29                              body=str(n))
30         while self.response is None:
31             self.connection.process_data_events() #非阻塞版的start_consumer()
32             print("no msg....")
33             time.sleep(0.5)
34         return int(self.response)
35 
36 if __name__ == "__main__":
37     fibonacci_rpc = FibonacciRpcClient()
38     print(" [x] Requesting fib(30)")
39     response = fibonacci_rpc.call(10)
40     print(" [.] Got %r" % response)

 

注:

  1. 我是想不阻塞,而是想每过一段时间,就过来检查一下,就不能用start_consumer,而是用connection.process_data_evevts(),它是不阻塞的,如果收到消息就收到,收不到消息也返回,就继续往下执行。
  2. reply_to就是想让服务器执行完命令之后,把结果返回到这个queue里面。
  3. 在while self.respose is None中的代码我可以不做time.sleep,我这边可以发消息给服务器端,这个消息不一定按顺序发给服务器端,如果不做self.corr_id == props.correlation_id的验证,那数据就可能对不上了。

3.2、RPC Server

 

 1 import pika
 2 
 3 connection = pika.BlockingConnection(pika.ConnectionParameters(host="localhost"))
 4 channel = connection.channel()
 5 channel.queue_declare(queue="rpc_queue")
 6 
 7 def fib(n):
 8     "斐波那契数列"
 9     if n == 0:
10         return 0
11     elif n == 1:
12         return 1
13     else:
14         return fib(n-1)+fib(n-2)
15 
16 
17 def on_request(ch,method,props,body):
18     n = int(body)
19     print(" [.] fib(%s)" % n)
20     response = fib(n)
21     ch.basic_publish(exchange="",
22                      routing_key=props.reply_to,
23                      properties=pika.BasicProperties(correlation_id=\
24                      props.correlation_id),#props的是客户端的发过来的信息,这边把correlation_id返回给客户端做验证
25                      body=str(response))
26     ch.basic_ack(delivery_tag=method.delivery_tag)
27 
28 channel.basic_qos(prefetch_count=1)
29 channel.basic_consume(on_request,queue="rpc_queue")
30 
31 print(" [x] Awaiting RPC requests")
32 channel.start_consuming()

 

注:props.reply_to,这个就是客户端返回过来的queue。

问:如果客户端和服务用的是同一个queue,会有什么影响?

答:如果客户端也发到rpc_queue中,那么客户端就会收到自己的消息,就会形成一个死循坏,把自己给玩死了。

 

posted @ 2018-04-09 09:57  东郭仔  阅读(128)  评论(0)    收藏  举报