[rabbitmq] python版本(五) 主题交换机

更详细的可以看这里: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]...\n" % 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的路由键

    扫描二维码关注公众号,回复: 11058643 查看本文章
  • 绑定键为 #.* 的队列会获取到一个名为..的路由键的消息吗?它会取到一个路由键为单个单词的消息吗?
    会获取到,"#.*"可以匹配长度大于1的路由键,名为..其实就是长度为3的路由键,可以匹配;单个单词即是长度为1也可以匹配

  • a.*.# 和 a.#的区别在哪儿?
    前者为a开头,但单词长度至少为2的一个路由键,后者长度至少为1就可以

猜你喜欢

转载自www.cnblogs.com/lonelyisland/p/12757927.html