基于Python语言使用RabbitMQ消息队列(一)
介绍
RabbitMQ 是一个消息中间人(broker): 它接收并且发送消息. 你可以把它想象成一个邮局: 当你把想要寄出的信放到邮筒里时, 你可以确定邮递员会把信件送到收信人那里. 在这个比喻中, RabbitMQ 就是一个邮筒, 同时也是邮局和邮递员 .
和邮局的主要不同点在于RabbitMQ不处理纸质信件, 而是 接收(accepts), 存储(stores) 和转发(forwards)二进制数据块 —— 消息(messages).
在RabbitMQ中有一些自己的行业术语要了解 .
生产(producing)在这里的意思就是发送(sending). 一个发送消息的程序就是生产者( producer) :
队列(queue) 可以看做是邮筒的别名 ,它存在于RabbitMQ中. 虽然消息在RabbitMQ和你的应用程序中流转, 但它只能被存储在队列当中. 一个队列只受到主机的内存和磁盘的限制, 它实际上是个大的消息缓冲区. 许多生产者可以发送消息到一个队列, 许多消费者可以从队列中接收数据. 下面是队列的示意图:
消费(consuming) 与接收(receiving)有相似的含义. 消费者(consumer)就是等待接收消息的程序 :
要注意的是 生产者, 消费者, 和中间人不必在相同的主机上,实际上大多数情况下它们都不在同一台主机上
(using the pika 0.10.0 Python client)
在教程的这部分里我们用Python写两个小程序; 一个 发送消息的生产者 (sender), 一个接收消息并把它打印出来的消费者consumer (receiver)
在下面的图例中, “P” 代表我们的生产者 , “C”代表我们的消费者. 中间的盒子是一个队列—由RabbitMQ 维持的消息缓冲区.
我们的整体设计大致如下图所示:
生产者发送消息到名为 “hello”的 队列. 消费者从那个队列中接收消息
RabbitMQ 库
RabbitMQ遵循 AMQP 0.9.1, 这是一个开源的, 多用途(general-purpose)的消息发送协议.
针对RabbitMQ,在不同语言中有多种客户端可用. 在本教程系列中我们将使用 Pika, 这是由RabbitMQ团队推荐的 Python客户端. 你可以使用pip安装.
发送
我们的第一个程序send.py 将会发送一条消息到队列中. 我们要做的第一件事是和 RabbitMQ 服务建立连接.
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
- 1
- 2
- 3
- 4
- 5
现在我们已经建立了一个到本地机器的中间人(broker)的连接, 如果想要连接到不同的机器上的中间人,只要把‘localhost’替换成指定的名字和IP地址即可.
下一步, 在发送前我们要确保接收的队列存在. 如果我们发送消息到一个不存在的地址, RabbitMQ 会把消息丢弃掉. 我们创建一个名为‘hello’的队列 ,把消息发送到这个队列中:
channel.queue_declare(queue='hello')
- 1
到这里我们准备好要发送消息了,第一条消息只是一个简单的字符串“hello world!”,把它发送到队列中
In RabbitMQ 一条消息从不会被直接发送到队列, 它会先经过一个交换所(exchange). 但我我们不要被细节缠住 ‒ 你会在教程的第三部分了解更多关于交换所的内容. 目前我们需要知道的就是如何使用有空字符串所指定的默认交换所。这个交换所允许我们准确指定消息应该前往哪个队列。 队列名由 “routing_key”参数指定:
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print(" [x] Sent 'Hello World!'")
- 1
- 2
- 3
- 4
退出程序前我们需要确保网络缓冲区(network buffers)被冲刷(flushed),并且我们的消息真的被发送到了RabbitMQ. 这只需要通过关闭连接来完成:
connection.close()
- 1
接收
我们的第二个程序 receive.py 将会从队列接收消息并且打印出来。
同样,我们首先要连接到RabbitMQ 服务。 连接到Rabbit的代码同前面的一样 。
下一步,同先前一样,要确保队列存在. 使用queue_declare 创建队列是一个幂等(idempotent)操作 ‒ 我们想运行多少次这个命令都可以, 但只有一个队列被创建.
channel.queue_declare(queue='hello')
- 1
你可能会问为什么又一次声明队列 ‒ 我们在前面的代码中已经声明过一次. 如果我们确定队列存在的话的话可以避免那么做. 例如 send.py 已经运行了. 但我们不确定哪个程序先运行. 在这种情况下最好在两个程序中都声明一下,这是一个好的习惯。
列出所有队列
如果你想查看RabbitMQ 拥有哪些队列,有多少消息在其中.你可以使用 rabbitmqctl 工具:
sudo rabbitmqctl list_queues
在 Windows中:rabbitmqctl.bat list_queues
从队列中接收消息会稍微复杂一些. 通过给队列提供一个callback 函数来实现. 无论何时接收到消息, 这个callback 函数都会被 Pika 库调用. 在我们这里,这个函数会打印出接收到的消息.
def callback(ch, method, properties, body):
print(" [x] Received %r" % body)
- 1
- 2
下一步, 我们需要告诉 RabbitMQ 这个callback函数应该从我们的 “hello”队列中接收消息:
channel.basic_consume(callback,
queue='hello',
no_ack=True)
- 1
- 2
- 3
这里的“no_ack ”参数会在后面有介绍.
最后我们加一个等待接收数据并且在必要时运行回调函数的永远不会终止的循环.
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
- 1
- 2
整合
send.py的完整代码:
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
receive.py的完整代码:
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
def callback(ch, method, properties, body):
print(" [x] Received %r" % body)
channel.basic_consume(callback,
queue='hello',
no_ack=True)
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
现在在终端运行我们的程序. 首先,启动一个消费者程序, 这会持续运行来等待接收消息:
python receive.py
- 1
下面是在我的Ubuntu终端上的运行结果:
现在来启动生产者. 生产者程序在运行完会退出:
python send.py
- 1
在回头看之前打开的消费者程序终端,已经接到了消息:
我们已经学会了如何向一个命名队列中发送和接收消息. 下一节我们来构建一个简单的工作队列(work queue)
基于Python语言使用RabbitMQ消息队列(一)的更多相关文章
- 基于Python语言使用RabbitMQ消息队列(六)
远程过程调用(RPC) 在第二节里我们学会了如何使用工作队列在多个工人中分布时间消耗性任务. 但如果我们想要运行存在于远程计算机上的方法并等待返回结果该如何去做呢?这就不太一样了,这种模式就是常说的远 ...
- 基于Python语言使用RabbitMQ消息队列(五)
Topics 在前面教程中我们改进了日志系统,相比较于使用fanout类型交易所只能傻瓜一样地广播,我们用direct获得了选择性接收日志的能力. 虽然使用direct类型交易所改进了我们的系统,但它 ...
- 基于Python语言使用RabbitMQ消息队列(四)
路由 在上一节我们构建了一个简单的日志系统.我们能够广播消息给很多接收者. 在本节我们将给它添加一些特性——我们让它只订阅所有消息的子集.例如,我们只把严重错误(critical error)导入到日 ...
- 基于Python语言使用RabbitMQ消息队列(三)
发布/订阅 前面的教程中我们已经创建了一个工作队列.在一个工作队列背后的假设是每个任务恰好会传递给一个工人.在这一部分里我们会做一些完全不同的东西——我们会发送消息给多个消费者.这就是所谓的“发布/订 ...
- 基于Python语言使用RabbitMQ消息队列(二)
工作队列 在第一节我们写了程序来向命名队列发送和接收消息 .在本节我们会创建一个工作队列(Work Queue)用来在多个工人(worker)中分发时间消耗型任务(time-consuming tas ...
- python学习之-- RabbitMQ 消息队列
记录:异步网络框架:twisted学习参考:www.cnblogs.com/alex3714/articles/5248247.html RabbitMQ 模块 <消息队列> 先说明:py ...
- Python并发编程-RabbitMQ消息队列
RabbitMQ队列 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议. MQ全称为Message Queue, 消息队列 ...
- Python RabbitMQ消息队列
python内的队列queue 线程 queue:不同线程交互,不能夸进程 进程 queue:只能用于父进程与子进程,或者同一父进程下的多个子进程,进行交互 注:不同的两个独立进程是不能交互的. ...
- openresty 学习笔记番外篇:python访问RabbitMQ消息队列
openresty 学习笔记番外篇:python访问RabbitMQ消息队列 python使用pika扩展库操作RabbitMQ的流程梳理. 客户端连接到消息队列服务器,打开一个channel. 客户 ...
随机推荐
- asp.net 在AcquireRequestState事件中判断登陆验证。
Global中添加AcquireRequestState事件. protected void Application_AcquireRequestState(object sender, EventA ...
- 【TopCoder】SRM159 DIV2总结
250分题:给出一些规则,问街道上哪些地方可以停车. 简单的模拟题,考察每条规则是否成立即可. 代码:StreetParking 500分题:实现集合的交,并和差运算. 交运算:一个数组放到集合中,遍 ...
- this 机制的四种规则
江湖人称,谁调用 this,this 就指向谁. 那么 this 到底绑定或者引用的是哪个对象环境呢,以下便是四种规则 1. 默认绑定全局变量 function fn() { console.log( ...
- C语言:内存字节对齐详解
转:http://blog.csdn.net/arethe/article/details/2548867 一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论 ...
- DNS 转发配置
DNS 转发配置 我们配置DNS是只能解析我们定义的zone的,我们没有定义的是不能解析的. 配置DNS转发就可以解析其他互联网上的域名了,前提是这个域名在互联网中的企业在使用. 也就是说这个域名已经 ...
- 断点续传JAVA实现
支持H5 Video标签播放,迅雷下载 /** * 断点续传工具 * @author lxycx_xc * 时间:2017年11月30日 */ public class BreakpointResum ...
- scope的继承
本文转载自: http://www.tuicool.com/articles/63iEref angular中scope的继承与js的原型继承有密切的联系,首先回顾一下js的继承: function ...
- 20145230 《Java程序设计》第8周学习总结
20145230 <Java程序设计>第8周学习总结 教材学习内容 NIO与NIO2 NIO使用频道(Channel)来衔接数据节点,在处理数据时,NIO可以设定缓冲区(Buffer)容量 ...
- Qt配置USBCAN通信
周立功为CAN通信提供了动态库:官方提供了很多相关动态库和lib等,如图 ,其中kerneldlls里还有很多动态库,还有一个配置文件.其实这么多的文件,如果我们只用到USBCAN2通信,只需要ker ...
- 网络安全-跨站脚本攻击XSS(Cross-Site Scripting)
一.XSS攻击简介 作为一种HTML注入攻击,XSS攻击的核心思想就是在HTML页面中注入恶意代码,而XSS采用的注入方式是非常巧妙的. 在XSS攻击中,一般有三个角色参与:攻击者.目标服务器.受害者 ...