一、发布/订阅

分发一个消息给多个消费者(consumers)。这种模式被称为“发布/订阅”。

为了描述这种模式,我们将会构建一个简单的日志系统。它包括两个程序——第一个程序负责发送日志消息,第二个程序负责获取消息并输出内容。

在这个日志系统中,所有正在运行的接收方程序都会接受消息。我们用其中一个接收者(receiver)把日志写入硬盘中,另外一个接受者(receiver)把日志输出到屏幕上。

最终,日志消息被广播给所有的接受者(receivers)。

二、交换器(Exchanges)

  • 发布者(producer)是发布消息的应用程序。
  • 队列(queue)用于消息存储的缓冲。
  • 消费者(consumer)是接收消息的应用程序。

RabbitMQ消息模型的核心理念是:发布者(producer)不会直接发送任何消息给队列。事实上,发布者(producer)甚至不知道消息是否已经被投递到队列。

发布者(producer)只需要把消息发送给一个交换器(exchange)。交换器非常简单,它一边从发布者方接收消息,一边把消息推入队列。交换器必须知道如何处理它接收到的消息,是应该推送到指定的队列还是是多个队列,或者是直接忽略消息。这些规则是通过exchange type来定义的。

有几个可供选择的交换器类型:

AMQPEXTYPEDIRECT

AMQPEXTYPEFANOUT

AMQPEXTYPEHEADER  or AMQPEXTYPETOPIC

这里主要说明AMQPEXTYPE_FANOUT。先创建一个fanout类型的交换器,命名为logs:

$exchange->setName('logs');
$exchange->setType(AMQP_EX_TYPE_FANOUT);
$exchange->declareExchange();

fanout交换器很简单,你可能从名字上就能猜测出来,它把消息发送给它所知道的所有队列。这正是我们的日志系统所需要的。

现在,我们就可以发送消息到一个具名交换器了:

$exchange->publish($message, '');

三、临时队列

给一个队列命名是很重要的——我们需要把工作者(workers)指向正确的队列。如果你打算在发布者(producers)和消费者(consumers)之间共享同队列的话,给队列命名是十分重要的。

但是这并不适用于我们的日志系统。我们打算接收所有的日志消息,而不仅仅是一小部分。我们关心的是最新的消息而不是旧的。为了解决这个问题,我们需要做两件事情。

首先,当我们连接上RabbitMQ的时候,我们需要一个全新的、空的队列。我们可以手动创建一个随机的队列名,或者让服务器为我们选择一个随机的队列名(推荐)。我们只要在调用$queue->declareQueue();方法的时候,不提供queue参数就可以了:

$queue = new AMQPQueue($channel);
$queue->setFlags(AMQP_EXCLUSIVE);
$queue->declareQueue();

这时候我们可以通过$queue->getName();获得已经生成的随机队列名。它可能是这样子的:amq.gen-U0srCoW8TsaXjNh73pnVAw==。

第二步,当与消费者(consumer)断开连接的时候,这个队列应当被删除。我们可以使用exclusive标识。$queue->setFlags(AMQP_EXCLUSIVE);

四、绑定

我们已经创建了一个fanout类型的交换器和一个队列。现在我们需要告诉交换器如何发送消息给我们的队列。交换器和队列之间的关系我们称之为绑定(binding)。

$queue->bind($exchangeName, $queue->getName());

现在,logs交换器将会把消息添加到我们的队列中。

五、代码整合

  1、生产者:send_log.php

  

<?php

/**
* PHP amqp(RabbitMQ) Demo-3
*/ $exchangeName = 'logs';
$message = empty($argv[1]) ? 'info:Hello World!' : ' '.$argv[1]; $connection = new AMQPConnection(array('host' => '127.0.0.1', 'port' => '5672', 'vhost' => '/', 'login' => 'guest', 'password' => 'guest'));
$connection->connect() or die("Cannot connect to the broker!\n"); $channel = new AMQPChannel($connection);
$exchange = new AMQPExchange($channel);
$exchange->setName($exchangeName);
$exchange->setType(AMQP_EX_TYPE_FANOUT);//把消息发送给它所知道的所有队列
$exchange->declareExchange(); $exchange->publish($message, '');
var_dump("[x] Sent $message"); $connection->disconnect();

  2、消费者:receive_logs.php

  

<?php

/**
* PHP amqp(RabbitMQ) Demo-3
*/
$exchangeName = 'logs'; $connection = new AMQPConnection(array('host' => '127.0.0.1', 'port' => '5672', 'vhost' => '/', 'login' => 'guest', 'password' => 'guest'));
$connection->connect() or die("Cannot connect to the broker!\n"); $channel = new AMQPChannel($connection); $exchange = new AMQPExchange($channel);
$exchange->setName($exchangeName);
$exchange->setType(AMQP_EX_TYPE_FANOUT);//把消息发送给它所知道的所有队列
$exchange->declareExchange(); $queue = new AMQPQueue($channel);
$queue->setFlags(AMQP_EXCLUSIVE);//当与消费者(consumer)断开连接的时候,这个队列应当被删除
$queue->declareQueue();//创建一个随机的队列名
$queue->bind($exchangeName, ''); var_dump('[*] Waiting for messages. To exit press CTRL+C');
while (TRUE) {
$queue->consume('callback');
}
$connection->disconnect(); function callback($envelope, $queue) {
$msg = $envelope->getBody();
var_dump(" [x] Received:" . $msg);
$queue->nack($envelope->getDeliveryTag());
}

这样我们就完成了。如果你想把日志保存到文件中,只需要打开控制台输入:

$ php receive_logs.php > logs_from_rabbit.log

如果你想在屏幕中查看日志,那么打开一个新的终端然后运行:

$ php receive_logs.php

当然还要发送日志:

$ php send_log.php
 

RabbitMq学习4-发布/订阅(Publish/Subscribe)的更多相关文章

  1. RabbitMQ入门(3)——发布/订阅(Publish/Subscribe)

    在上一篇RabbitMQ入门(2)--工作队列中,有一个默认的前提:每个任务都只发送到一个工作人员.这一篇将介绍发送一个消息到多个消费者.这种模式称为发布/订阅(Publish/Subscribe). ...

  2. RabbitMQ学习总结 第四篇:发布/订阅 Publish/Subscribe

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  3. RabbitMQ入门教程(五):扇形交换机发布/订阅(Publish/Subscribe)

    原文:RabbitMQ入门教程(五):扇形交换机发布/订阅(Publish/Subscribe) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. ...

  4. (转) RabbitMQ学习之发布/订阅(java)

    http://blog.csdn.net/zhu_tianwei/article/details/40887733 参考:http://blog.csdn.NET/lmj623565791/artic ...

  5. RabbitMQ入门:发布/订阅(Publish/Subscribe)

    在前面的两篇博客中 RabbitMQ入门:Hello RabbitMQ 代码实例 RabbitMQ入门:工作队列(Work Queue) 遇到的实例都是一个消息只发送给一个消费者(工作者),他们的消息 ...

  6. RabbitMQ入门教程——发布/订阅

    什么是发布订阅 发布订阅是一种设计模式定义了一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象.这个主题对象在自身状态变化时,会通知所有的订阅者对象,使他们能够自动更新自己的状态. 为了描述这种 ...

  7. 【Redis数据库】命令学习笔记——发布订阅、事务、脚本、连接等命令汇总

    本篇基于redis 4.0.11版本,学习发布订阅.事务.脚本.连接的相关命令. Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. 序号 ...

  8. rabbitmq消息队列——"发布订阅"

    三."发布订阅" 上一节的练习中我们创建了一个工作队列.队列中的每条消息都会被发送至一个工作进程.这节,我们将做些完全不同的事情--我们将发送单个消息发送至多个消费者.这种模式就是 ...

  9. RabbitMQ/JAVA (发布/订阅模式)

    发布/订阅模式即生产者将消息发送给多个消费者. 下面介绍几个在发布/订阅模式中的关键概念-- 1. Exchanges (转发器) 可能原来我们都是基于一个队列发送和接收消息.现在介绍一下完整的消息传 ...

  10. 4.RabbitMQ系列之发布/订阅模式

    我们把一个消息转发给多个消费者,这种模式称之为发布-订阅模式 1.交换器(Exchange) RabbitMq消息模式的核心思想是:一个生产者并不会直接往一个队列中发送消息,事实上,生产者根本不知道它 ...

随机推荐

  1. Python 爬虫十六式 - 第一式:HTTP协议

    HTTP:伟大而又无闻的协议 学习一时爽,一直学习一直爽!   Hello,大家好啊,我是Connor,一个从无到有的技术小白.有的人一说什么是HTTP协议就犯愁,写东西的时候也没想过什么是HTTP协 ...

  2. BZOJ 1901 洛谷 P2617 ZOJ 2112 Dynamic Rankings

    以下时空限制来自zoj Time limit 10000 ms Memory limit 32768 kB OS Linux Source Online Contest of Christopher' ...

  3. CVPR 2018 DeepGlobe

    在刚刚结束的CVPR2018: DeepGlobe Road Extraction Challenge(全球卫星图像道路提取)比赛中,北京邮电大学信息与通信工程学院模式识别实验室张闯老师指导的研究生周 ...

  4. JMS学习八(ActiveMQ消息持久化)

    ActiveMQ的消息持久化机制有JDBC,AMQ,KahaDB和LevelDB,还有一种内存存储的方式,由于内存不属于持久化范畴,而且如果使用内存队列,可以考虑使用更合适的产品,如ZeroMQ.所以 ...

  5. 使用WebStorm运行vue项目

    在WebStorm中怎么打开一个已有的项目,这个不用多说,那么如何运行一个vue项目呢? 1.点击下图中右上角的红框. 2.在出现的弹框中选中左上角“+”下的“npm”,如下图所示. 3.选中第二步的 ...

  6. 好题Islands

    Orz yjc 吊打候选队 不好的思路是枚举森林的m块,这样DP显然会涉及n当做某一维,最多只能卷积优化一下 生成函数什么的n太大不用想 考虑m,k比较小,能不能把n变成一个系数,而不是维度 所以就是 ...

  7. javadoc生成文档

    标签(空格分隔): javadoc java生成html的文档: 要生成注释文档html格式,java里面提供一个工具:javadoc 例如: javadoc -d myhelp -author -v ...

  8. centos7没有IP地址

    查看网卡 ip addr查看网卡 我截图中有ip,是因为我已经设置过了. eth0是对外的网卡,我们接下来设置这个网卡,你的网卡名字可能和我的不一样. 修改网卡 修改/etc/sysconfig/ne ...

  9. windows server 2008 r2 配置ftp (FileZilla Server )

    1.需要个ftp 2.在华为云内部,用IIS,配置后如果用主动模式,客户端需要配置后客户端需要做配置才能访问,去掉√,见下图. 3.华为云的教程,配被动需要把1024以上的端口都放开,不安全! 但客户 ...

  10. leetcode-mid-others-150. Evaluate Reverse Polish Notation

    mycode   42.30%. 注意:如果不考虑符号,-1//3=-1而不是等于0,因为是向下取整 class Solution(object): def evalRPN(self, tokens) ...