rabbitmq

一.rabbitmq 安装

  详情见:http://www.cnblogs.com/yangh965/p/5862347.html

  windows:  

  1.安装Erlang

  2.安装rabbitmq

  3.安装插件

  4.http://127.0.0.1:15672/ 测试

  5.添加用户

  linux:

 

 二.安装第三方库pika

   pip3 install pika

 

三.rabbitmy消息队列的结束

  rabbitmq与queue的区别:rabbitmy支持两个程序之间的交互

  官网有详细的教程:http://www.rabbitmq.com/

  Broker:简单来说就是消息队列服务器实体。 
  Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。 
  Queue:消息队列载体,每个消息都会被投入到一个或多个队列。 
  Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。 
  Routing Key:路由关键字,exchange根据这个关键字进行消息投递。 
  vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。 
  producer:消息生产者,就是投递消息的程序。 
  consumer:消息消费者,就是接受消息的程序。 
  channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务

 

四:简单的消息队列(一对一,开启多个消费者也是一个生产者向一个消费者逐一的发送数据)

  注: 防止消费者挂掉,需要增加确认消息

    ch.basic_ack(delivery_tag = method.delivery_tag)

    no_ack=False 

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

import  pika
#建立一个连接实例
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672)) #默认端口,可不写
#创建一个管道
channel = connection.channel()
#创建一个队列,如果存在则不创建
channel.queue_declare(queue='hello')
#通过exchange 将消息发送到队列
channel.basic_publish(
    exchange="",  #基本的队列,参数为空
    routing_key='hello',#队列的名字
    body='hello world!'#消息内容
)
print('[x] Sent "hello world"')
#关闭连接
connection.close()
生产者
#!/usr/bin/env python
# --*-- encoding:utf-8 --*--
import pika
import time
#创建一个连接的实例
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
#创建一个管道
channel = connection.channel()
#创建一个名为hello的队列,如果服务器中存在,则不创建
channel.queue_declare(queue='hello')

#回调函数
def callback(ch,method,properties,body):
    print('[x] Received %s'% body)
    #模拟服务器宕机的情形 ,在10秒内终止程序运行
    time.sleep(10)
    #告诉生产者,消息出来完成
    ch.basic_ack(delivery_tag=method.delivery_tag)

#消费消息
channel.basic_consume(
    callback, #如果有消息,调用回调函数处理
    queue='hello',#到哪个队列取消息
    # no_ack=True # 不写的话使用:默认no_ack=False,如果机器宕机,重新启动,还可以接受到未处理的队列消息  一般不写
                  # no_ack=True  写的话,机器宕机,以前的队列消息丢失
)

print('[*] Waiting for messages,To exit press CTRL+C')
#开始消费消息
channel.start_consuming()
消费者

  注:防止rabbitmq服务器挂掉,那么需要持久化

    channel.queue_declare(queue='hello2',durable=True)

    properties=pika.BasicProperties(

      delivery_mode=2,# 使消息持久化

    )

  注:按能力分配消息

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

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

import pika
#创建一个连接的实例
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672))
#创建一个管道
channel = connection.channel()
#创建队列,队列名不能与存在的相同,持久化durable=True
channel.queue_declare(queue='hello2',durable=True)
#向队列中放入消息
channel.basic_publish(
    exchange='', #简单模式
    body='hello world',#消息内容
    routing_key='hello2', #队列名
    properties=pika.BasicProperties(
        delivery_mode=2,# 使消息持久化
    )
)
print('[x] Sent "Hello World"')
#关闭连接
connection.close()
生产者
#!/usr/bin/env python
# --*-- encoding:utf-8 --*--
import pika
import time
#创建一个连接实例
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
#创建一个管道
channel = connection.channel()
#声明一个队列,不存在则创建,持久化
channel.queue_declare(queue='hello2',durable=True)
#回调函数
def callback(ch,method,properties,body):
    print('[x] Received %r'%body)
    time.sleep(10)
    ch.basic_ack(delivery_tag=method.delivery_tag)  # 向生产者发送处理完成的消息
#类似权重,按能力分发消息
channel.basic_qos(prefetch_count=1)
#消费消息
channel.basic_consume(
    callback,  #设置回调函数
    queue='hello2', #设置队列
    #no_ack=True # 一般不写
)
print('[*] Waiting for message,To exit press CTRL+C')
#开始消费
channel.start_consuming()
消费者

 

五.复杂的消息队列(exchange)(一对多,一个生产者向多个消费者同时发相同的数据)

  exchange三种类型:

    fanout: 所有绑定到此exchange的queue都可以接收消息

    direct: 通过routingKey和exchange决定的那个唯一的queue可以接收消息

    topic: 所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息

 

  1.fanout:广播消息

    需要queue和exchange绑定,因为消费者不是和exchange直连的,消费者是连在queue上,queue绑定在exchange上,消费者只会在queue里取消息

#!/usr/bin/env python
# --*-- encoding:utf-8 --*--
import pika
import sys
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672))
channel = connection.channel()
#声明广播管道,不需要声明队列
channel.exchange_declare(
    exchange='logs',#交换机的名字
    type='fanout'
)
# message = ' '.join(sys.argv[1:])
message = 'info:hello world'
channel.basic_publish(
    exchange='logs', #指定交换机
    routing_key='',# 此处为空,必须有
    body=message
)
print('[x] Sent %s'% message)
connection.close()
发布者
#!/usr/bin/env python
# --*-- encoding:utf-8 --*--
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
#声明广播管道
channel.exchange_declare(
    exchange='logs',
    type='fanout'
)
#不指定队列名字,rabbit会随机分配一个名字,exclusive=True会在使用此队列的消费者在断开后,将队列自动删除
result = channel.queue_declare(exclusive=True)
#获取随机的队列的名字
queue_name = result.method.queue
print('random queue name:',queue_name)
#将随机生成的队列绑定到管道上
channel.queue_bind(
    exchange='logs', #指定交换机的名字
    queue=queue_name
)
print('[*] Waiting for los ,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()
订阅者

  2.direct:关键字发送消息

    指定向某个队列发送消息,消费者的routing_key 要包含生产者的routing_key ,才能发送成功

#!/usr/bin/env python
# --*-- encoding:utf-8 --*--
import pika
import sys

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672))
channel=connection.channel()
#声明交换机有选择的接收消息
channel.exchange_declare(
    exchange='direct_logs',
    type='direct'
)
#重要的程度级别 默认为info  severity一个字符串
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, #根据severity 匹配要发送的队列
    body=message
)
print(" [x] Sent %r:%r" % (severity, message))
connection.close()
生产者
#!/usr/bin/env python
# --*-- encoding:utf-8 --*--
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
#获取运行脚本参数 ,severties 多个字符串,只要有一个与 发送端相同,就可以处理消息
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] %s:%s'%(method.routing_key,body))

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

channel.start_consuming()
消费者

  3.topic:模糊匹配

    # 表示可以匹配 0 个 或 多个 单词

    *  表示只能匹配 一个 单词

#!/usr/bin/env python
# --*-- encoding:utf-8 --*--
import pika
import sys

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672))
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,
    body=message
)
print(" [x] Sent %r:%r" % (routing_key, message))
connection.close()
生产者
#!/usr/bin/env python
# --*-- encoding:utf-8 --*--
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

binding_keys = sys.argv[1:]
if not binding_keys:
    sys.stderr.write('Usage:%s [info] [warning] [error]\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
    )

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

def callback(ch,method,properties,body):
    print('[x] %s:%s'%(method.routing_key,body))

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

channel.start_consuming()
消费者

    python publ.py  aaa.info sbsb

    python subs.py  *.info                    #可以匹配成功

    python publ.py  aaa.info sbsb

    python subs.py  #                     #可以匹配成功

 六.rabbitmq rpc实现

  参考:http://blog.csdn.net/fgf00/article/details/52872730

posted @ 2017-06-12 10:47  1916  阅读(131)  评论(0)    收藏  举报