链条传动

砥砺前行,不忘初心!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

使用方法

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
RabbitMQ基础

http://www.cnblogs.com/wupeiqi/articles/5132791.html

RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。
MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)
来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通
常是用于诸如远程过程调用的技术。排队指的是应用程序通过队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。

简单来说:
RabbitMQ是在服务器上实现的一个消息队列,用于进行不同应用程序间的通信(应用程序不直接建立连接通信,
而是通过RabbiMQ实现的消息队列来进行数据交互)


python操作RabbitMQ的模块:pika
安装:pip3 install pika

例:生产者消费者模型
对于RabbitMQ来说,生产和消费不再针对内存里的一个Queue对象,而是某台服务器上的RabbitMQ Server实现的消息队列。

"""

import pika

# 生产者
connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))   # 创建连接RabbitMQ服务端的连接

channel = connection.channel()  # 创建一个新频道

channel.queue_declare(queue='hello')  # 频道中定义一个hello队列---如果该队列已存在,则忽略该句代码

# 开始向hello队列中发数据
channel.basic_publish(exchange='',
                      routing_key='hello',
                      body='hello,world!')

print("[x] Send 'hello world!'")
connection.close()  # 关闭连接



#################################################################################################################
# 消费者
# connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))
# channel = connection.channel()
# channel.queue_declare('hello')
#
#
# # 回调函数
# # 参数:ch:频道(channel)、method:队列名字(hello)、# properties:连接RabbitMQ会有一些基本属性、body:从队列中取到的内容
# def callback(ch, method, properties, body):
#     print('[x] Received %r' % body)
#
# # 从hello队列中取数据,取完后会自动调用callback函数
# channel.basic_consume(callback,
#                       queue='hello',
#                       no_ack=True)
#
# print('[*] Waiting for messages,To exit press CTRL+C')
# channel.start_consuming()
基本
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
RabbitMQ使用---默认no_ack=False

no_ack=False,如果消费者遇到情况(its channel is closed, connection is closed, or TCP connection is lost)挂掉了,
那么,RabbitMQ会重新将该任务添加到队列中。

简单来说:
no_ack=False   表示消费者从队列中取数据,处理完毕后,需要告诉RabbitMQ服务端该条数据已处理,如果没有告诉,则服务端会认为消费
者出现问题,该条数据没有处理完成,会重新将该数据放回队列



no_ack=False  能保证数据不丢失,取出来的数据一定要处理完成才行,没处理完就会将数据放回,等待下次处理---------对性能有一定影响
no_ack=True   不能保证数据不丢失,不管取出来的数据是否处理完成,取出来就不管了---------性能比为False时高
"""

import pika

# 消费者
connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))
channel = connection.channel()
channel.queue_declear('hello')


# 回调函数
# 参数:ch:频道(channel)、method:队列名字(hello)、# properties:连接RabbitMQ会有一些基本属性、body:从队列中取到的内容
# def callback(ch, method, properties, body):
#     print('[x] Received %r' % body)
#
# # 从hello队列中取数据,取完后会自动调用callback函数
# channel.basic_consume(callback,
#                       queue='hello',
#                       no_ack=True)

# 回调函数
# 参数:ch:频道(channel)、method:队列名字(hello)、# properties:连接RabbitMQ会有一些基本属性、body:从队列中取到的内容
def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)
    import time
    time.sleep(10)
    print('OK')
    ch.basic_ack(delivery_tag=method.delivery_tag)   # 告诉RabbitMQ服务端数据已处理完成

# 从hello队列中取数据,取完后会自动调用callback函数
channel.basic_consume(callback,
                      queue='hello',
                      no_ack=False)   # no_ack=False,消费者处理任务后,需要告诉服务端数据已处理完成

print('[*] Waiting for messages,To exit press CTRL+C')
channel.start_consuming()
接收端保证数据不丢失
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
RabbitMQ使用
数据不丢失:在向RabbitMQ队列发数据的时候,告诉RabbitMQ服务端发送的数据要进行持久化保存,这样RabbitMQ服务端就会将收到的数据持久
化保存,即使RabbitMQ服务端出现故障,也不会影响该持久化的数据

"""
import pika

# 生产者
connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))   # 创建连接RabbitMQ服务端的连接

channel = connection.channel()  # 创建一个新频道

channel.queue_declare(queue='hello')  # 频道中定义一个hello队列---如果该队列已存在,则忽略该句代码

# 开始向hello队列中发数据
channel.basic_publish(exchange='',
                      routing_key='hello',
                      body='hello,world!',
                      properties=pika.BasicProperties(delivery_mode=2)   # 告诉RabbitMQ服务端,数据要持久化保存
                      )

print("[x] Send 'hello world!'")
connection.close()  # 关闭连接
发布端发送数据持久化
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
RabbitMQ使用

消息获取顺序:
默认消息队列里的数据是按照顺序被消费者拿走,例如:消费者1 去队列中获取 奇数 序列的任务,消费者2去队列中获取 偶数 序列的任务。

channel.basic_qos(prefetch_count=1) 表示谁来谁取,不再按照奇偶数排列
"""

import pika

# 消费者
connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))
channel = connection.channel()
channel.queue_declear('hello')


# 回调函数
# 参数:ch:频道(channel)、method:队列名字(hello)、# properties:连接RabbitMQ会有一些基本属性、body:从队列中取到的内容
def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)
    import time
    time.sleep(10)
    print('OK')
    ch.basic_ack(delivery_tag=method.delivery_tag)   # 告诉RabbitMQ服务端数据已处理完成

channel.basic_qos(prefetch_count=1)    # 表示取数据的时候,服务端按照队列顺序谁来谁取(默认每个消费者按照一定间隔来取数据)

# 从hello队列中取数据,取完后会自动调用callback函数
channel.basic_consume(callback,
                      queue='hello',
                      no_ack=False)   # no_ack=False,消费者处理任务后,需要告诉服务端数据已处理完成

print('[*] Waiting for messages,To exit press CTRL+C')
channel.start_consuming()
接收端按顺序取消息队列数据
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
发布订阅-----exchange type:fanout

发布订阅和简单的消息队列区别在于,发布订阅会将消息发送给所有的订阅者,而消息队列中的数据被消费一次便消失。所以,RabbitMQ实现发
布和订阅时,会为每一个订阅者创建一个队列,而发布者发布消息时,会将消息放置在所有相关队列中。
"""

import pika
import sys

# 发布者
connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))  # 创建连接
channel = connection.channel()   # 创建频道

# 创建一个exchange,已存在则忽略该代码
channel.exchange_declare(exchange='logs_fanout',
                         type='fanout')

message = ' '.join(sys.argv[1:]) or "info: Hello World!"
# 使用exchange发消息(exchange和队列的映射关系可以由订阅者做,订阅者将订阅的消息队列和exchange关联)
channel.basic_publish(exchange='logs_fanout',
                      routing_key='',
                      body=message)

print(" [x] Sent %r" % message)
connection.close()


#######################################################################################################################
# # 订阅者
# connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))  # 创建连接
# channel = connection.channel()  # 创建频道
#
# # 创建exchange,已存在则忽略该代码
# channel.exchange_declare(exchange='logs_fanout',
#                          type='fanout')
# # 随机创建队列,并随机取名
# result = channel.queue_declare(exclusive=True)
# queue_name = result.method.queue
#
# # 创建exchange和消息队列的映射关系
# channel.queue_bind(exchange='logs_fanout',
#                    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()
RabbitMQ发布订阅
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
关键字发送----exchang type:direct

之前示例,发送消息时明确指定某个队列并向其中发送消息,RabbitMQ还支持根据关键字发送,即:队列绑定关键字,发送者将数据根据关键字
发送到消息exchange,exchange根据 关键字 判定应该将数据发送至指定队列。
"""
import pika
import sys

# 生产者
connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))  # 创建连接
channel = connection.channel()   # 创建频道

# 创建exchange
channel.exchange_declare(exchange='logs_direct',
                         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='logs_direct',
                      routing_key=severity,
                      body=message)

print(" [x] Sent %r:%r" % (severity, message))
connection.close()  # 关闭


#######################################################################################################################
# 消费者
connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))   # 创建连接
channel = connection.channel()   # 创建频道

# 创建exchange
channel.exchange_declare(exchange='logs_direct',
                         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='logs_direct',
                       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()
RabbitMQ关键字发送
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
模糊匹配----exchange type:topic

在topic类型下,可以让队列绑定几个模糊的关键字,之后发送者将数据发送到exchange,exchange将传入”路由值“和 ”关键字“进行匹配,匹配成功,则将数据发送到指定队列。

# 表示可以匹配 0 个 或 多个 单词
*  表示只能匹配 一个 单词

发送者路由值              队列中
old.boy                 old.*  -- 匹配
old.boy.python          old.*  -- 不匹配(不能匹配'.'),只能匹配一个单词
old.boy.python          old.#  -- 匹配
"""
import pika
import sys

# 生产者
connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))   # 创建连接
channel = connection.channel()    # 创建频道

# 创建exchange
channel.exchange_declare(exchange='log_topic',
                         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='log_topic',
                      routing_key=routing_key,
                      body=message)

print(" [x] Sent %r:%r" % (routing_key, message))

connection.close()

#######################################################################################################################
# 消费者
connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.22'))    # 创建连接
channel = connection.channel()   # 创建频道

# 创建exchange
channel.exchange_declare(exchange='log_topic',
                         type='topic')

# 创建随机队列
result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue

binding_keys = sys.argv[1:]
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='log_topic',
                       queue=queue_name,
                       routing_key=binding_key)   # 队列绑定模糊匹配的关键字,如:old.#

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


# 回调函数
def callback(ch, method, properties, body):
    print(" [x] %r:%r" % (method.routing_key, body))
    ch.basic_ack(delivery_tag=method.delivery_tag)

# 获取队列消息
channel.basic_consume(callback,
                      queue=queue_name,
                      no_ack=False)

channel.start_consuming()
RabbitMQ模糊匹配

 

原理示意图

RabbitMQ发布订阅示意图

 

RabbitMQ关键字发送示意图

 

RabbitMQ模糊匹配示意图

 

posted on 2016-12-02 14:47  链条君  阅读(199)  评论(0编辑  收藏  举报