day11-rabbitmq

RabbitMQ:消息队列,用于独立程序通信

依赖语言:erlang

一、简单通信

 1 # ---------------------------------------------
 2 # send端(producer)
 3 # 建立socket->声明管道->声明queue->通过一个exchange发送内容至queue->关闭连接
 4 # ---------------------------------------------
 5 
 6 import pika
 7 # 通过这个实例先建立一个socket
 8 # rabbitmq默认端口15672,在python中使用pika模块
 9 # 所有的socket 传输都是bytes类型
10 connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
11 # 声明一个管道
12 channel = connection.channel()
13 # 声明queue, 名为test
14 # durable持久化队列,重启rabbitmq服务不会丢队列,但会丢消息,durable服务端和客户端都需写明
15 channel.queue_declare(queue="hello", durable=True)
16 # 发送
17 # 一个生产者对应多个消费者是采用轮询机制,公平的依次发给每一个消费者,每个消费者消费1个
18 # 假如一个生产者对应3个消费者,生产者发第一条消息,第一个消费者消费,生产者发第二条信息,第二个消费者消费...
19 channel.basic_publish(exchange="",
20                       routing_key="hello",   # queue的名字
21                       body="hello world",   # body是发送内容
22                       properties=pika.BasicProperties(delivery_mode=2,),    # 使消息持久化
23                       )
24 print("[x] Sent 'hello world'")
25 # 关闭连接
26 connection.close()

 

 1 # ---------------------------------------------
 2 # receive端(consumers)
 3 # 创建socket连接->创建管道->声明queue->创建回调函数callback->消费的消息->开启消费
 4 # ---------------------------------------------
 5 
 6 
 7 import pika
 8 # 使用byte格式
 9 # 建立一个socket连接
10 # 消费者和生产者不一定在同一台机器上
11 connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
12 # 创建一个管道
13 channel = connection.channel()
14 # 如果你确认queue已经存在可不写,但我们不确定是生产者还是消费者先运行,如果消费者先运行,此时这个queue不存在,会直接报错
15 # durable持久化,重启rabbitmq服务不会丢消息,durable服务端和客户端都需写明
16 channel.queue_declare(queue="test", durable=True)
17 
18 
19 def callback(ch, method, properites, body):
20     print("--->", ch, method, properites)
21     print(" [x] Received %r" % body)
22     # 手动确认消息已被消费
23     ch.basic_ack(delivery_tag=method.delivery_tag)
24 
25 # 设置消费限额,设置为1则表示当前在处理的消息超过1条就不给此消费端发消息
26 channel.basic_qos(prefetch_count=1)
27 # 消费消息
28 channel.basic_consume(
29     callback,   # 如果收到消息,就调用callback函数来处理消息
30     queue="test",    # queue的名字
31     # no_ack=True,    # 表示不关心消息是否处理完,一般情况不加,如果客户端没有确认,rabbitmq不会把消息删除
32     )
33 print(' [*] Waiting for messages. To exit press CTRL+C')
34 
35 # 这个start只要一启动,就一直运行,它不止收一条,而是永远收下去,没有消息就在这边卡住
36 # 正式开始收消息
37 channel.start_consuming()

二、广播模式

生产者:

import pika
import sys

connection = pika.BlockingConnection(pika.ConnectionParameters(
        host='localhost'))
channel = connection.channel()

# ---------------------------------------------------------------
# 1. fanout广播模式
# fanout广播模式,实时消息,如果没有消费端接收就消息就没了
channel.exchange_declare(exchange='logs',
                         type='fanout')

message = "info: Hello World!"
# routing_key为空,广播模式不绑定队列
channel.basic_publish(exchange='logs',
                      routing_key='',
                      body=message)


# -----------------------------------------------------------------
# 2.direct广播模式, 实时消息,有选择地接收消息,关键字发送
channel.exchange_declare(exchange='direct_logs',
                         type='direct')

severity = sys.argv[1] if len(sys.argv) > 1 else 'info'
message = ' '.join(sys.argv[2:]) or 'Hello World!'
channel.basic_publish(exchange='direct_logs',
                      routing_key=severity,
                      body=message)

# -----------------------------------------------------------------
# 3.topic更细致的消息过滤
channel.exchange_declare(exchange='topic_logs',
                         type='topic')

routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info'
message = ' '.join(sys.argv[2:]) or 'Hello World!'
channel.basic_publish(exchange='topic_logs',
                      routing_key=routing_key,
                      body=message)

# --------------------------------------------------------------------
print(" [x] Sent %r" % message)
connection.close()

消费者:

 1 import pika
 2 import sys
 3 
 4 connection = pika.BlockingConnection(pika.ConnectionParameters(
 5         host='localhost'))
 6 channel = connection.channel()
 7 
 8 # ---------------------------------------------------------------
 9 # 1. fanout广播模式
10 channel.exchange_declare(exchange='logs',
11                          type='fanout')
12 
13 # 生成一个随机的queue
14 # 不指定queue名字,rabbit会随机分配一个名字,exclusive=True会在使用此queue的消费者断开后,自动将queue删除
15 result = channel.queue_declare(exclusive=True)
16 queue_name = result.method.queue
17 
18 # 队列绑定转发器,消费者只会从队列里拿消息
19 channel.queue_bind(exchange='logs',
20                    queue=queue_name)
21 
22 # -----------------------------------------------------------------
23 # 2.direct广播模式
24 
25 channel.exchange_declare(exchange='direct_logs',
26                          type='direct')
27 
28 result = channel.queue_declare(exclusive=True)
29 queue_name = result.method.queue
30 
31 # 接收消息类型
32 severities = sys.argv[1:]
33 if not severities:
34     sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
35     sys.exit(1)
36 
37 # 遍历绑定
38 for severity in severities:
39     channel.queue_bind(exchange='direct_logs',
40                        queue=queue_name,
41                        routing_key=severity)
42 
43 # -----------------------------------------------------------------
44 # 3.topic更细致的消息过滤
45 # 接收所有消息#
46 # 接收以mysql开头的消息: mysql.*
47 # 接收以info结尾的消息: *.info
48 channel.exchange_declare(exchange='topic_logs',
49                          type='topic')
50 
51 result = channel.queue_declare(exclusive=True)
52 queue_name = result.method.queue
53 
54 # 接收消息内容
55 binding_keys = sys.argv[1:]
56 if not binding_keys:
57     sys.stderr.write("Usage: %s [binding_key]...\n" % sys.argv[0])
58     sys.exit(1)
59 
60 for binding_key in binding_keys:
61     channel.queue_bind(exchange='topic_logs',
62                        queue=queue_name,
63                        routing_key=binding_key)
64 
65 # -----------------------------------------------------------------
66 print(' [*] Waiting for logs. To exit press CTRL+C')
67 
68 
69 def callback(ch, method, properties, body):
70     print(" [x] %r" % body)
71 
72 channel.basic_consume(callback,
73                       queue=queue_name,
74                       no_ack=True)
75 
76 channel.start_consuming()

三、RPC=>remote procedure call

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(30)
40     print(" [.] Got %r" % response)

Server端:

 1 import pika
 2 import time
 3 connection = pika.BlockingConnection(pika.ConnectionParameters(
 4         host='localhost'))
 5 
 6 channel = connection.channel()
 7 
 8 channel.queue_declare(queue='rpc_queue')
 9 
10 def fib(n):
11     if n == 0:
12         return 0
13     elif n == 1:
14         return 1
15     else:
16         return fib(n-1) + fib(n-2)
17 
18 def on_request(ch, method, props, body):
19     n = int(body)
20 
21     print(" [.] fib(%s)" % n)
22     response = fib(n)
23 
24     ch.basic_publish(exchange='',
25                      routing_key=props.reply_to,
26                      properties=pika.BasicProperties(correlation_id = \
27                                                          props.correlation_id),
28                      body=str(response))
29     ch.basic_ack(delivery_tag = method.delivery_tag)
30 
31 channel.basic_qos(prefetch_count=1)
32 channel.basic_consume(on_request, queue='rpc_queue')
33 
34 print(" [x] Awaiting RPC requests")
35 channel.start_consuming()

 

posted @ 2018-03-27 17:48  不知所以  阅读(89)  评论(0)    收藏  举报