发布订阅模式

什么时发布订阅模式

把消息发送给多个订阅者。也就是有多个消费端都完整的接收生产者的消息

换句话说 把消息广播给多个消费者

消息模型的核心

RabbitMQ不发送消息给队列,生产者也不知道消息发送到队列

生产者只发送消息到exchange 交换器,

exchange一方面从生产者接收消息,另一方面把消息推送到队列中。

exchange必须知道如何处理接收到的消息 。是加到特定队列中,还是添加到多个队列中,还是放弃。这个是由他的类型来决定 。

而消息的类型有四种,分别是

Direct,Topic,headers,fanout

fanout消息类型

fanout消息类型可以把消息广播到所有队列中。

指定exchange的名称为logs,routingkey设置为空。

 channel.BasicPublish(exchange: "logs",
routingKey: "",
basicProperties: null,
body: body);

为队列的名称指定一个随机数

var queueName = channel.QueueDeclare().QueueName;
channel.QueueDeclare(queue: queueName,
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);

经过对之前代码的改造

我们定义了一个可以广播类型的exchange和一个随机名字的队列 ,

现在我们需要把他们绑定起来。

channel.QueueBind(queue: queueName, exchange: "logs", routingKey: "");

生产者的代码

  1. 创建连接
  2. 创建信道
  3. 声明类型为fanout的消息
  4. publish发送消息
static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: "logs", type: "fanout");
for (var i = 0; i < 10; i++)
{
string message = "Hello World!this is message "+i;
var body = Encoding.UTF8.GetBytes(message);
var properties = channel.CreateBasicProperties();
properties.Persistent = true; channel.BasicPublish(exchange: "logs",
routingKey: "",
basicProperties: null,
body: body); Console.WriteLine(" [x] Sent {0},id={1}", message,i);
Thread.Sleep(1000);
}
} Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}

消费者代码

  1. 创建连接
  2. 创建信道
  3. 声明类型为fanout的消息
  4. 声明一个队列
  5. 把队列然后绑定到信道上
  6. 接收消息
static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: "logs", type: "fanout");
var queueName = channel.QueueDeclare().QueueName;
channel.QueueBind(queue: queueName, exchange: "logs", routingKey: "");
//以下是区别生产者的
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (sender, e) =>
{
var body = e.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("Received {0}", message);
Thread.Sleep(3000);//模拟耗时任务 ,
Console.WriteLine("Received over");
channel.BasicAck(deliveryTag: e.DeliveryTag, multiple: false);
};
channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer);
Console.WriteLine("");
Console.ReadLine();
} } }

测试结果

启了一个生产者,两个消费者,生产者发送10条消息 ,两个消费者都收到了10条消息

友情提示

我对我的文章负责,发现好多网上的文章 没有实践,都发出来的,让人走很多弯路,如果你在我的文章中遇到无法实现,或者无法走通的问题。可以直接在公众号《爱码农爱生活 》留言。必定会再次复查原因。让每一篇 文章的流程都能顺利实现。

RabbitMQ入门学习系列(四) 发布订阅模式的更多相关文章

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

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

  2. RabbitMQ入门学习系列(二),单生产者消费者

    友情提示 我对我的文章负责,发现好多网上的文章 没有实践,都发出来的,让人走很多弯路,如果你在我的文章中遇到无法实现,或者无法走通的问题.可以直接在公众号<爱码农爱生活 >留言.必定会再次 ...

  3. rabbitMQ学习笔记(四) 发布/订阅消息

    前面都是一条消息只会被一个消费者处理. 如果要每个消费者都处理同一个消息,rabbitMq也提供了相应的方法. 在以前的程序中,不管是生产者端还是消费者端都必须知道一个指定的QueueName才能发送 ...

  4. RabbitMQ入门学习系列(六) Exchange的Topic类型

    快速阅读 介绍exchange的topic类型,和Direct类型相似,但是增加了"."和"#"的匹配.比Direct类型灵活 Topic消息类型 特点是:to ...

  5. RabbitMQ入门学习系列(五) Exchange的Direct类型

    快速阅读 利用Exchange的Direct类型,实现对队列的过滤,消费者启动以后,输入相应的key值,攻取该key值对应的在队列中的消息 . 从一节知道Exchange有四种类型 Direct,To ...

  6. RabbitMQ入门学习系列(七) 远程调用RPC

    快速阅读 生产者和消费者启动以后,都有一个接收事件,消费者是接收事件是处理调用方法以后等待生产者的返回,生产者的接收事件是处理接收生产者发送的消息,进行处理.消费者发送的时候要在回调队列中加入一个标识 ...

  7. ActiveMQ入门系列三:发布/订阅模式

    在上一篇<ActiveMQ入门系列二:入门代码实例(点对点模式)>中提到了ActiveMQ中的两种模式:点对点模式(PTP)和发布/订阅模式(Pub & Sub),详细介绍了点对点 ...

  8. RabbitMQ学习第三记:发布/订阅模式(Publish/Subscribe)

    工作队列模式是直接在生产者与消费者里声明好一个队列,这种情况下消息只会对应同类型的消费者. 举个用户注册的列子:用户在注册完后一般都会发送消息通知用户注册成功(失败).如果在一个系统中,用户注册信息有 ...

  9. RabbitMQ指南之三:发布/订阅模式(Publish/Subscribe)

    在上一章中,我们创建了一个工作队列,工作队列模式的设想是每一条消息只会被转发给一个消费者.本章将会讲解完全不一样的场景: 我们会把一个消息转发给多个消费者,这种模式称之为发布-订阅模式. 为了阐述这个 ...

随机推荐

  1. FreeRTOS计数型信号量

    API函数 //创建 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #define xSemaphoreCreateCounting( uxMaxCount ...

  2. Spring @Transactional注解不起作用解决办法及原理分析

    Transactional失效场景介绍 第一种 Transactional注解标注方法修饰符为非public时,@Transactional注解将会不起作用.例如以下代码. 定义一个错误的@Trans ...

  3. Java中重载(overloading)和重写(Overriding)的区别

    一:方法的重载 (1)方法重载指在类中定义方法名相同,参数不同的不同的多个方法(返回值类型可随意,不能以返回类型作为重载函数的区分标准). 参数不同表现: 1.参数的个数不同 2.参数的类型不同 3. ...

  4. Android笔记(六十一)动态添加组件

    想要一个功能,点击按钮,可以在已有的布局上,新添加一组组件. 动态的创建组件,本质上还是创建组件,只不过是在程序中根据逻辑来创建.大致步骤是找到要创建控件的位置,然后将要创建的组件添加进去. 看代码: ...

  5. [ipsec][crypto] 有点不同的数字证书到底是什么

    前言 前言是在写完了全文之后回头补的.本意是想完全抽象的把证书的抽象逻辑意义表达出来,因为你能找到的大部分 资料都深陷在技术细节与行业规范里.只有其型没有其理,没有什么比理解一个事物的内在合理性更有乐 ...

  6. WebService知识点

    Web Services简介: 什么是Web Services? Web Services 是应用程序组件 Web Services 使用开放协议进行通信 Web Services 是独立的(self ...

  7. WebSocketServer

    @Component @ServerEndpoint(value = "/endpoint/ws") public class WebSocketServer { private ...

  8. SpringCloud学习心得—1.3—Eureka与REST API

      SpringCloud学习心得—1.3—Eureka与REST API Eureka的REST API接口 API的基本访问 Eureka REST APIEureka 作为注册中心,其本质是存储 ...

  9. JavaScript解析机制之变量提升

    1.什么是预解析? 在当前作用域下,JS 运行之前,会把带有 var 和 function 关键字的事先声明,并在内存中安排好.(这个过程也可以理解为变量提升)然后再从上到下执行 JS 语句(预解析只 ...

  10. 解决问题:Jupyter Notebook启动不会自动打开浏览器,每次都要自己打开浏览器输入网址

    1.找到anaconda下的anaconda prompt并打开(或者CMD)都可以 2.在anaconda prompt里面输入:jupyter notebook --generate-config ...