RabbitMQ学习笔记(三) 发布与订阅
发布与订阅
在我们使用手机发送消息的时候,即可以选择给单个手机号码发送消息,也可以选择多个手机号码,群发消息。
前面学习工作队列的时候,我们使用的场景是一个消息只能被一个消费者程序实例接收并处理,但是如果想要群发消息,仅凭之前学到的东西是实现不了的。
所以这里需要引入RabbitMQ的发布与订阅模式。
Exchange
什么是Exchange?
RabbitMQ通信模型的核心思想是消息生产者不会直接发送消息到消息队列,生产者程序也不知道他产生的消息是否发送到了一个消息队列中。
实际上消息生产者只会发送消息到一个Exchange对象。Exchange是英语中交换的意思,这RabbitMQ中它实际就是一个消息的中转站,一方面它会接收所有与它绑定的生产者程序实例产生的消息,一方面它有会根据自身的定义将消息发送到不同的消息队列中。不同的Exchange类型决定了它会将消息发送到一个特定的消息队列,还是多个消息队列。

Exchange有四种类型
- direct
- topic
- headers
- fanout
RabbitMQ的发布和订阅模式会使用fanout类型的Exchange。
“fanout”在英语中是扇出、展开的意思,这种类型的Exchange会将收到的一条消息,发送到多个消息队列中,而不同的消息消费者实例监听不同的消息队列,从而实现消息广播的功能。
如何设置Exchange
我们可以使用channel对象中的ExchangeDeclare方法来声明Exchange
channel.ExchangeDeclare("logs", "fanout");
这个方法的第一个参数是Exchange的名称,第二个参数是Exchange的类型。
当我们调用channel对象的BasicPublish方法发送消息的时候,我们可以设置Exchange参数
public static void BasicPublish(this IModel model, string exchange, string routingKey, IBasicProperties basicProperties, byte[] body);
例:
channel.BasicPublish(exchange: "logs", routingKey: "", basicProperties: null, body: body);
默认Exchange
回想上一章工作队列的例子,会发现之前才发布消息的时候,我们有传递一个空 exchange
channel.BasicPublish(exchange: "", routingKey: "work_queue", basicProperties: properties, body: body );
那为什么消息会正确的发送到消息消费者程序实例呢?
这个其实是RabbitMQ的一个默认设置,当发送消息时,如果将exchange设置为空字符串,系统会自动启用一个默认的Exchange, 这个Exchange会把消息自动添加到第二个参数routeingKey指定的消息队列中(在上一章的例子中,即work_queue消息队列),所以消息消费者程序实例才能正确的接收消息。
临时消息队列
当我们群发消息的时候,我们需要为每个消息消费者实例创建一个名字独特的消息队列。
但是这里我们只是关注群发消息,而不想去关注为消息队列起名字这件事情。
RabbitMQ提供了一种临时消息队列,来帮助我们简化这个操作。
当我们在声明消息队列的时候,不传递任何参数,生成的就是一个临时消息队列
channel.QueueDeclare();
而如果想获得这个消息队列的名字,我们可以从它的QueueName属性中获取。
var queueName = channel.QueueDeclare().QueueName;
这个queueName是RabbitMQ帮我们动态随机生成,例:amq.gen-JzTY20BRgKO-HjmUJj0wLg.
Exchange和消息队列绑定
当我们创建了一个 Exchange之后,我们需要设置Exchange给那些消息队列发送消息,Exchange和消息队列之间的关系叫做Binding(绑定)

在channel对象中有一个QueueBind的方法来帮助我们完成这一操作
channel.QueueBind(queue: queueName, exchange: "logs", routingKey: "");
修改程序
现在我们修改一下我们之前的发送消息程序,将它改造成一个消息群发器。
Send
- 声明一个名为broadcast的Exchange
- 修改发送消息部分的代码,现在直接发送到创建的Exchange中
static void Main(string[] args)
{
var factory = new ConnectionFactory()
{
HostName = "localhost"
};
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare("broadcast", "fanout");
string message = args[0];
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "broadcast",
routingKey: "",
basicProperties: null,
body: body
);
Console.WriteLine("[x] Sent {0}", message);
}
}
}
Receive
- 使用临时消息队列
- 将Exchange和临时消息队列绑定
static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare("broadcast", "fanout");
var queueName = channel.QueueDeclare().QueueName;
channel.QueueBind(queue: queueName, exchange: "broadcast", routingKey: "");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("[x] Received {0}", message);
};
channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
Console.Read();
}
}
}
最终效果
我们启动1个Send程序,2个Receive程序。

RabbitMQ学习笔记(三) 发布与订阅的更多相关文章
- StackExchange.Redis学习笔记(五) 发布和订阅
Redis命令中的Pub/Sub Redis在 2.0之后的版本中 实现了 事件推送的 发布订阅命令 以下是Redis关于发布和订阅提供的相关命令 SUBSCRIBE channel [channe ...
- rabbitMQ学习笔记(四) 发布/订阅消息
前面都是一条消息只会被一个消费者处理. 如果要每个消费者都处理同一个消息,rabbitMq也提供了相应的方法. 在以前的程序中,不管是生产者端还是消费者端都必须知道一个指定的QueueName才能发送 ...
- jw player学习笔记三---发布到其它网站
一.通过官网发布向导 登陆 http://www.longtailvideo.com,注册一个账号,进入你的用户管理中心,如下图 然后按提示,一步步操作,就会得到js代码了. 二.自己服务器发布 &l ...
- rabbitMQ学习笔记(三) 消息确认与公平调度消费者
从本节开始称Sender为生产者 , Recv为消费者 一.消息确认 为了确保消息一定被消费者处理,rabbitMQ提供了消息确认功能,就是在消费者处理完任务之后,就给服务器一个回馈,服务器就会将 ...
- RabbitMQ学习笔记三:Java实现RabbitMQ之与Spring集成
搭建好maven项目环境,加入RabbitMQ依赖包 <dependency> <groupId>org.springframework.amqp</groupId> ...
- RabbitMQ学习笔记五:RabbitMQ之优先级消息队列
RabbitMQ优先级队列注意点: 1.只有当消费者不足,不能及时进行消费的情况下,优先级队列才会生效 2.RabbitMQ3.5以后才支持优先级队列 代码在博客:RabbitMQ学习笔记三:Java ...
- 官网英文版学习——RabbitMQ学习笔记(一)认识RabbitMQ
鉴于目前中文的RabbitMQ教程很缺,本博主虽然买了一本rabbitMQ的书,遗憾的是该书的代码用的不是java语言,看起来也有些不爽,且网友们不同人学习所写不同,本博主看的有些地方不太理想,为此本 ...
- RabbitMQ学习笔记(五) Topic
更多的问题 Direct Exchange帮助我们解决了分类发布与订阅消息的问题,但是Direct Exchange的问题是,它所使用的routingKey是一个简单字符串,这决定了它只能按照一个条件 ...
- Part1.2 、RabbitMQ -- Publish/Subscribe 【发布和订阅】
python 目录 (一).交换 (Exchanges) -- 1.1 武sir 经典 Exchanges 案例展示. (二).临时队列( Temporary queues ) (三).绑定(Bind ...
- RabbitMQ学习系列三-C#代码接收处理消息
RabbitMQ学习系列三:.net 环境下 C#代码订阅 RabbitMQ 消息并处理 http://www.80iter.com/blog/1438251320680361 http://www. ...
随机推荐
- phpstudy配置本地https
百度经验(me'i经过测试) 首先申请免费的ssl证书,很多地方都可以申请.我是在腾讯云!如图 下载证书备份好.以免丢失.解压下载的证书,里面有4个文件夹相对应不同的安装环境,我们用的是Apache, ...
- redis的雪崩与穿透原理的浅理解
首先列一下主要说什么, 1.什么是Redis缓存的雪崩? 2.什么是Redis缓存的穿透? 3.Redis缓存崩溃会怎么样? 4.怎么预防Redis缓存崩溃? 1.什么是Redis缓存的雪崩? 举个栗 ...
- 谈谈代码中的this
js中我们常常会遇到this,this的具体指向问题对于很多同学来说是很懵懂的:就想lz刚开始接触时候就是一脸的懵逼,经常被一些题目转的眼花缭乱.那么今天lz就跟大家一起交流一下这个this的指向问题 ...
- ODM、JDM、OEM概念
OEM (Original Equipment Manufacturer) - 原始设备制造商 委托生产,或者说“代工生产”,其含义是品牌厂商不直接制造产品,而是负责设计和开发新产品,控制销售“渠道” ...
- BZOJ1991 : Pku2422 The Wolves and the Sheep
将每个不是障碍的格子标号,设三只狼的位置分别为$A,B,C$,羊的位置在$D$.合法状态中强行限制$A<B<C$,这样状态数只有$\frac{n^8}{6}\approx 1.6\time ...
- centOS7.3安装配置NFS服务
在安装和运行NFS服务中,发现了一个需要警惕的地方. 运行2个centOS7.3系统.由于前面一篇已经写了使用xshell进行远程,所以,直接远程进行操作: chen-01做为服务端,chen-02做 ...
- [JZOJ3615]【NOI2014模拟】数列(平面几何+二维线段树)
Description 给定一个长度为n的正整数数列a[i]. 定义2个位置的f值为两者位置差与数值差的和,即f(x,y)=|x-y|+|a[x]-a[y]|. 你需要写一个程序支持2种操作(k都是正 ...
- MVC Ajax上传文件
前台:首先要导入jQuery <html><head> <meta name="viewport" content="width=devic ...
- Keepalived+Nginx实现高可用Web负载均衡
1.安装编译 Nginx 所需的依赖包# yum install gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zli ...
- Linux shell编程— 命令替换
有两种方法可以将命令输出赋给变量 反引号字符(`) $()格式 命令替换允许你将shell 命令的输出赋给变量 要么用一对反引号把整个命令行围起来: testing=`data` 要么使用$()格式 ...