exchange工作模型有三种:fanout、direct、topic,具体如下:

一、发布订阅:fanout

(一) 基本原理:

    

  类似于分发报刊,每一张报纸上的内容都是全套的,读者分别从报纸上读取内容,

  发布订阅模式:将数据信息发布给所有订阅者,且数据队列中的信息被消费一次后就消失(no_ack=True)。

(二)具体流程:

  RabbitMQ实现发布订阅时,为每一个订阅者创建一个队列,发布者发布消息时将消息放置在所有相关队列中:

  1、生产者:声明一个交换机,并将数据信息载入,

  2、消费者:指定交换机,并声明一个队列绑定到该交换机,

  3、交换机:将生产者载入的数据信息,分发给绑定在其上的队列,每个队列收到的数据信息都是完整全套的,

  4、消费者:从声明的队列中获取数据信息,并执行回调函数,

(三)代码实现:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# exchange工作模式:fanout

import pika
import sys
# -----------------------生产者--------------------------------
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

# 声明一个交换机
channel.exchange_declare(exchange='logs',type='fanout')

# 将数据信息载入交换机
message = ''.join(sys.argv[1:]) or "info:hello world!"
channel.basic_publish(exchange='logs',      # 指定交换机
                      routing_key='',       # 不需要指定队列,此处为空
                      body=message)

print("[x] sent %r" % message)
connection.close()
生产者
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# exchange工作模式:fanout

import pika

#--------------------消费者----------------------
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

# 指定交换机
channel.exchange_declare(exchange='logs',type='fanout')

# 声明专用队列并获取队列名称
result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue

# 队列绑定交换机
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] %r" % body)

channel.basic_consume(callback,
                      queue=queue_name,
                      no_ack=True)

# 阻塞,等待队列新消息
channel.start_consuming()
消费者

二、关键字发送:direct

    

  数据队列除了绑定交换机,还要绑定关键字(每一个队列可以绑定多个关键字;关键字不能为空,否则报错),

  发送消息时,将数据信息和关键字同时载入交换机,交换机根据绑定在其上的数据队列的关键字,判断是否将数据发送给它,

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# exchange工作模式:direct

import pika
import sys
# -----------------------生产者--------------------------------
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

# 声明一个交换机
channel.exchange_declare(exchange='direct_logs',type='direct')

# 将routing_key和body载入指定的交换机
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,         # 指定routing_key
                      body=message)                 # 指定数据信息

print("[x] sent %r %r" % (severity,message))
connection.close()
生产者
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# exchange工作模式:direct

import pika
import sys
#--------------------消费者----------------------
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

# 指定交换机
channel.exchange_declare(exchange='direct_logs',type='direct')

# 声明专用队列并获取队列名称
result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue

# 输入routing_key,可多个,但不能为空,
severities = sys.argv[1:]
if not severities:
    sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
    sys.exit(1)

# 队列绑定交换机和多个routing_key
for severity in severities:
    channel.queue_bind(
        exchange='direct_logs',
        queue=queue_name,
        routing_key=severity
    )

print('[*] waiting for logs. To exit press CTRL+C')

# 从队列获取消息并自执行回调函数
def callback(ch, method, properties, body):
    print(" [x] %r" % body)

channel.basic_consume(callback,
                      queue=queue_name,
                      no_ack=True)

# 阻塞,等待队列新消息
channel.start_consuming()
消费者

三、模糊匹配:topic

    

  与上述direct模式相似,但绑定的关键字可以是模糊匹配:* 表示匹配一个单词,# 表示匹配0个或多个单词,如:

  发送者路由值               队列中

  old.boy.python           old.* -- 不匹配

  old.boy.python           old.# -- 匹配
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# exchange工作模式:topic

import pika
import sys

# -----------------------生产者--------------------------------
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

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,     # 指定routing_key
                      body=message)                # 指定数据信息

print("[x] sent %r %r" % (routing_key,message))
connection.close()
生产者
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# exchange工作模式:topic

import pika
import sys

#--------------------消费者----------------------
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

channel.exchange_declare(
    exchange='topic_logs',
    type='topic',
)

result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue

routing_keys = sys.argv[1:]
if not routing_keys:
    sys.stderr.write("Usage: %s routing_keys......\n" % sys.argv[0])
    sys.exit(1)

for routing_key in routing_keys:
    channel.queue_bind(
        exchange='topic_logs',
        queue=queue_name,
        routing_key=routing_key,
    )

print('[*] waiting for logs. To exit press CTRL+C')

def callback(ch, method, properties, body):
    print(" [x] %r" % body)

channel.basic_consume(callback,
                      queue=queue_name,
                      no_ack=True)

channel.start_consuming()
消费者