更详细的可以看这里:https://rabbitmq.mr-ping.com/tutorials_with_python/[5]Topics.html
这里只是简要笔记,以便快速回忆
- 可以把topic看成是direct的一个升级版,可以匹配多个参数从而进行分类。
- 比如上图,Q1可以匹配所有orange颜色的东西;Q2可以匹配兔子/懒惰的。不同的分类词之间用'.'分割
- 对于上图".orange."和"..rabbit"只能匹配三个单词长度的routing key,"lazy.#"可以匹配任意长度的以lazy描述开头的routing key
- 注意命令行要用""而不能用''对routing key进行设定
- 如果传一个单词长度为4的routing key,比如"lazy.orange.male.rabbit"那么,不会匹配上面两种情况(长度不对),但是会匹配到"lazy.#"(只要lazy开头就可以,不论长度),消息最终传递到Q2
emit_log_topic.py
#!/usr/bin/env python
import pika
import sys
#连接
connection = pika.BlockingConnection(
pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
#声明交换机topic_logs 交换机类型topic
channel.exchange_declare(exchange='topic_logs', exchange_type='topic')
#routing_key设定为第一个命令行参数,如果没有则默认为'anonymous.info'
routing_key = sys.argv[1] if len(sys.argv) > 2 else 'anonymous.info'
#第二个命令行参数开始为发送的消息
message = ' '.join(sys.argv[2:]) or 'Hello World!'
#发布消息,交换机为topic_logs,routing key为上面设置的,body为消息体
channel.basic_publish(
exchange='topic_logs', routing_key=routing_key, body=message)
print(" [x] Sent %r:%r" % (routing_key, message))
connection.close()
receive_logs_topic.py
#!/usr/bin/env python
import pika
import sys
#连接
connection = pika.BlockingConnection(
pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
#声明交换机topic_logs,类型topic
channel.exchange_declare(exchange='topic_logs', exchange_type='topic')
#声明默认随机队列,名字存储在queue_name中;消费者退出后要进行处理
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
#第一个命令行参数开始为设定的binding_keys,一个或多个,少于一个报错
binding_keys = sys.argv[1:]
if not binding_keys:
sys.stderr.write("Usage: %s [binding_key]...
" % sys.argv[0])
sys.exit(1)
#绑定交换机和队列,设置routing_key
for binding_key in binding_keys:
channel.queue_bind(
exchange='topic_logs', queue=queue_name, routing_key=binding_key)
print(' [*] Waiting for logs. To exit press CTRL+C')
def callback(ch, method, properties, body):
print(" [x] %r:%r" % (method.routing_key, body))
channel.basic_consume(
queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()
运行截图:
图片说明:前三个terminal是从一开始就同步执行的,最后一个terminal是最后一步新建的
需要注意的地方是:
- '#' 匹配任意长度的单词,'*'匹配一个长度的单词
- 命令行参数需要用""而不能用'',否则不会匹配到
执行下边命令 接收所有日志:
python receive_logs_topic.py "#"
执行下边命令 接收来自”kern“设备的日志:
python receive_logs_topic.py "kern.*"
执行下边命令 只接收严重程度为”critical“的日志:
python receive_logs_topic.py "*.critical"
执行下边命令 建立多个绑定:
python receive_logs_topic.py "kern.*" "*.critical"
执行下边命令 发送路由键为 "kern.critical" 的日志:
python emit_log_topic.py "kern.critical" "A critical kernel error"
执行上边命令试试看效果吧。另外,上边代码不会对路由键和绑定键做任何假设,所以你可以在命令中使用超过两个路由键参数。
一些问答:
-
绑定键为 * 的队列会取到一个路由键为空的消息吗?
不会 "*"只能匹配单词长度为1的路由键
-
绑定键为 #.* 的队列会获取到一个名为..的路由键的消息吗?它会取到一个路由键为单个单词的消息吗?
会获取到,"#.*"可以匹配长度大于1的路由键,名为..其实就是长度为3的路由键,可以匹配;单个单词即是长度为1也可以匹配
-
a.*.# 和 a.#的区别在哪儿?
前者为a开头,但单词长度至少为2的一个路由键,后者长度至少为1就可以