1、发布端代码
# new_p.py
import pika
import sys
'''
什么是发布/订阅:
在上一个实例中,我们搭建了一个工作队列,每个任务只分发给一个工作者(worker)。
在本实例中,我们要做的跟之前完全不一样 即:分发一个消息给多个消费者(consumers)。这种模式被称为“发布/订阅”。
'''
# 发布订阅--发布者
# 建立一个链接
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
# 链接rabbitmq
channel = connection.channel()
# 在调用queue_declare方法的时候,不提供queue参数就可以创建一个随机名的队列
# result = channel.queue_declare()
# 使用交换机,这里并没有使用指定的一个队列,而是使用交换机,这里使用的交换机是扇形交换机,并且指定交换机名为logs
channel.exchange_declare(exchange='logs',exchange_type='fanout')
# 获取消息发布
message = ' '.join(sys.argv[1:]) or "info: Hello World!"
# 开始发布消息
# 值得注意的是:发布日志消息的程序看起来和之前的没有太大区别。最重要的改变就是我们把消息发送给 logs交换机 而不是 匿名交换机
# 你会注意到routing_key为空,这是因为,它的值会被扇型交换机(fanout exchange)忽略。
channel.basic_publish(exchange='logs',
routing_key='',
body=message)
print(" [x] Sent %r"%message)
# 关闭链接
connection.close()
'''
直连交换机(direct):
直连交换机(direct exchange)来代替。路由的算法很简单
交换机将会对绑定键 和路由键 进行精确匹配,从而确定消息该分发到哪个队列。
主题交换机(topic):
发送到主题交换机(topic exchange)的消息不可以携带随意什么样子的路由键(routing_key),
它的路由键必须是一个由.分隔开的词语列表。这些单词随便是什么都可以,但是最好是跟携带它们的消息有关系的词汇。
以下是几个推荐的例子:"stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit"。词语的个数可以随意,但是不要超过255字节。
* (星号) 用来表示一个单词.
# (井号) 用来表示任意数量(零个或多个)单词。
头交换机(headers):
首部交换机是忽略routing_key的一种路由方式。路由器和交换机路由的规则是通过Headers信息来交换的,这个有点像HTTP的Headers。将一个交换机声明成首部交换机,绑定一个队列的时候,定义一个Hash的数据结构,消息发送的时候,会携带一组hash数据结构的信息,当Hash的内容匹配上的时候,消息就会被写入队列。
扇型交换机(fanout):
扇型交换机(fanout exchanges)会忽略 绑定键routing_key,无论是 basic_publish or queue_bind
'''
2、消费/订阅端代码
import pika
import time
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs',exchange_type='fanout')
# 因为发布订阅用的是随机名队列,所以当与消费者断开连接的时候,这个队列应当被立即删除。exclusive标识符即可达到此目的。
result = channel.queue_declare(exclusive=True)
# 在之前的实例中我们都要事先知道,队列的名字,这里采用的就是默认获取
queue_name = result.method.queue
# 开始绑定:将消费者绑定到和交换机同一个频道,这样logs交换机发来的消息,消费者就可以收到了
channel.queue_bind(exchange='logs',queue=queue_name)
print(' [*] Waiting for logs. To exit press CTRL+C')
def callback(ch, method, properties, body):
print(" [x] Received %r" % body.decode())
time.sleep(body.decode().count('.') )
print(" [x] Done")
channel.basic_consume(callback,
queue=queue_name,
no_ack=True)
channel.start_consuming()
# rabbitmqctl list_bindings 列出所有现存的绑定。
# 绑定的另外一种理解:
# 绑定(binding)是指交换机(exchange)和队列(queue)的关系。
# 可以简单理解为:这个队列(queue)对这个交换机(exchange)的消息感兴趣。
3、如何运行
消费端:
python new_c.py
注意:这里多运行几个消费端,可以更好的理解
发布端:
python new_p.py hello world!
python new_p.py hello rabbitmq!
python new_p.py hello python!