RabbitMQ Exchange

Exchange:

1、fanout:

  广播模式:每个与此Exchange绑定的Queue,都会接收此Exchange的消息。

  之前提到的RabbitMQ消息分发中的channel.basic_publish 中的 exchange ='',这意味着将Producer发送的Message直接发送给名字为'hello'的队列中,而在Consumer则通过指定的队列名称来获取数据,但队列中的数据只有一份,如果想多个Consumer都可以得到相同数据的话,就需要每个Consumer都创建一个队列来获取数据,而原Consumer中声明的方法只会在RabbitMQ中创建一个名为'hello'的队列。

 

channel.queue_declare(queue = 'hello')

 

(1)创建队列:Consumer中声明队列的时候如果不给队列设置名称,RabbitMQ就会默认的给生成一个随机名称,而这个名称可以通过method.queue来获取。

result = channel.queue_declare(exclusive = True) #exclusive参数设置为True 是因为,如果Consumer关闭连接的话,就会queue就会被delete掉,所以设置成True.
queue_name = result.method.queue
print('queue name =',queue_name)

控制台输出
>>>
    queue name = amq.gen-LJjflCJqIW60S183_vUnJg

 

(2)创建Exchange:通过exchange_declare()方法就可以创建一个exchange.

 

channel.exchange_declare(exchange='logs',type = 'fanout')
# 参数 exchange 为声明的exchange的名字,type为exchange的类型这里这职位广播模式fanout。

 

(3)绑定:通过queue_bind将Exchange和queue绑定到一块

channel.queue_bind(exchange='log',queue = queue_name)

Producer:

(1)声明Exchange:通过exchange_declare()方法就可以创建一个exchange.

channel.exchange_declare(exchange='logs',type = 'fanout')

(2)通过basic_publish发送消息

channel.basic_publish(exchange = 'log', # 指定exchang
                          routing_key = '',  # 因为是通过exchange来发送消息,这里只需要为空
                          body = stdin_str,
                          )

完整版:

Producer:

import pika
# 创建一个connection
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
# 创建一个管道
channel = connection.channel()
channel.exchange_declare(exchange='log',type='fanout')
while True:
    stdin_str = input('>>>')
    channel.basic_publish(exchange = 'log',
                          routing_key = '',
                          body = stdin_str,
                          )
    print(" [x] Sent '{}'".format(stdin_str))

connection.close()

Consumer:

import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
#创建一个管道
channel = connection.channel()
#声明QUEUE
result = channel.queue_declare(exclusive = True)
# 获取queue名字
queue_name = result.method.queue
#声明一个Exchange 这指定名称为log,类型为fanout
channel.exchange_declare(exchange='log',type = 'fanout')
# 绑定Exchange和Queue
channel.queue_bind(exchange='log',queue = queue_name)
#回调函数
def callback(ch,method,properties,body):
    print(" [x] Received %r" % body.decode())

channel.basic_consume(callback,
                      queue =result.method.queue,
                      no_ack = False)

print(' [*] Waiting for messages. To exit press CTRL+C')
channel.basic_qos(prefetch_count=1)    #让Consumer谁执行完谁去Queue中领任务执行,以达到资源合理分配。
channel.start_consuming()

运行Producer,再运行多个Consumer后,当Producer发送消息的时候,这些Consumer都会接受到消息。

 

2、Direct:

  Direct Exchange就非常的简单了 ,他是通过绑定routing_key来给不同的队列发送消息。

 

(1)声明Exchange类型:

  

 

channel.exchange_declare(exchange = 'direct_logs',type = 'direct')

 

(2)绑定routing_key:

  在 queue_bing 中绑定队列和Exchange的时候指定 routing_key 的名称。

 

channel.queue_bind(exchange = 'log',queue = queue_name, routing_key = 'task')

 

(3)在Producer 的 publish中指定routing_key的名称

channel.basic_publish(exchange='direct_logs',routing_key='task',body=message)

3、通过不同的 routing_key 分发消息 info、warning、error

 Producer:

import pika
import sys
 
connection = pika.BlockingConnection(pika.ConnectionParameters(
        host='localhost'))
channel = connection.channel()
 
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)
print(" [x] Sent %r:%r" % (severity, message))
connection.close()

Consumer:

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
 
severities = sys.argv[1:]
if not severities:
    sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
    sys.exit(1)
 
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:%r" % (method.routing_key, body))
 
channel.basic_consume(callback,
                      queue=queue_name,
                      no_ack=True)
 
channel.start_consuming()

 3、Topic:主题模式

  如果说我们想实现的那种类似python中logger日志的功能,给日志分等级、分各个模块的话,我们就需要用到了Topic模式;在Topic中,我们是通过设置routing_key来区分我们的消息,routing_key的名称规范:用 . 来进行分割编写 ,如:logs.info 、config.error、bin.warning;并且在Topic模块中,可以用特殊字符来区分接收的信息的范围:

  *   代表任意 一个单词       *.info、error.*

  #   0个或者多个单词          # 、info.#

 

  需要注意的是:如果绑定的routing_key 为 # ,代表着匹配所有的信息。

Publisher:

import pika
import sys
 
connection = pika.BlockingConnection(pika.ConnectionParameters(
        host='localhost'))
channel = connection.channel()
 
channel.exchange_declare(exchange='topic_logs',
                         type='topic')  # 设置exchange的类型为topic
 
routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info' # 设置默认主题为.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:%r" % (routing_key, message))
connection.close()

subscriber:

import pika
import sys
 
connection = pika.BlockingConnection(pika.ConnectionParameters(
        host='localhost'))
channel = connection.channel()
 
channel.exchange_declare(exchange='topic_logs',
                         type='topic') # 声明exchange的类型为topit
 
result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue
 
binding_keys = sys.argv[1:] # 在控制台输入参数info、 warning、error
if not binding_keys:
    sys.stderr.write("Usage: %s [binding_key]...\n" % sys.argv[0])
    sys.exit(1)
 
for binding_key in binding_keys:
    channel.queue_bind(exchange='topic_logs',
                       queue=queue_name,
                       routing_key=binding_key) #绑定 routing_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(callback,
                      queue=queue_name,
                      no_ack=True)
 
channel.start_consuming()

 

 

 

posted @ 2017-07-20 16:20  LeeeetMe  阅读(283)  评论(0编辑  收藏  举报