上一个教程中,我们创建了一个work queue. 其中的每个task都会被精确的传送到一个worker. 这节,我们将会讲把一个message传送到多个consumers. 这种模式叫做publish/subscribe(发布/订阅).

为了说明这种模式,我们将创建一个简单的日志系统(logging system). 它由两个程序组成,一个是发送日志message并且另一个接收。

最重要的,发布的日志message将会被广播到所有的receivers

Exchangs

前面我们讲的包含下面的:producer,queue,consumer

它的主要思想是producer绝不直接发送任何message到queue. 很多情况下,producer甚至不知道一个message是否会被发送到任何queue.

如图,它会直接发送messages到一个exchange. 而对于exchange,一方面它接收来自producer的message,另一方面它把这些message推送到queues. 至于,messages是否会被发送一个特定的queue或者发送到很多queue或者丢弃,这些规则都由exchange type定义。

Exchange type: direct , topic , headers , fanout.

我们这节主要讲fanout,它会控制广播。

channel.ExchangeDeclare("logs", "fanout");

对于fanout exchange ,它会广播它收到的所有的messages 到它知道的所有的queue.

Listing exchanges

对于列出服务器上的exchanges , 你可以使用rabbitmqctl

sudo rabbitmqctl list_exchanges
The default exchange

在前面的教程中,我们不知道exchanges,但是我们仍然可以发送messages 到queues. 因为我们使用到了一个默认的exchange(a default exchange).这个默认的exchange是被空字符串(“”)定义。

回想下,我们之前怎样发送message

 var message = GetMessage(args);
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "", //默认的exchange
routingKey: "hello",
basicProperties: null,
body: body);

此时,messages会根据指定的routingKey被路由到queue.

现在,我们可以发布到指定的exchange.

var message = GetMessage(args);var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "logs",
routingKey: "",
basicProperties: null,
body: body);

Temporary queues

之前我们使用过很多指定名称的queues(例如hello和task_queue). 可以命名一个queue是很重要的,我们可以指定workers到同一个queue。 而且使你可以在多个producers和consumers之前共享这个queue.

We’re also interested only in currently flowing messages not in the old ones. 我们想要最新的message而不是仅仅之前的。

这需要解决两个事情。

  1. 首先,无论什么时候我们连接Rabbit,我们需要一个新的,空的queue。为了达到这个目的,我们可以创建一个带随机名称的queue。更好的办法,我们可以让服务器给我们选择一个随机的queue名称。
  2. 第二,一旦我们断开与consumer的连接,这个queue应该被自动删除。

在.NET客户端中,我们使用下面的语句创建一个带随机名称的queue (when we supply no parameters to QueueDeclare() we create a non-durable, exclusive, autodelete queue with a generated name)

var queueName = channel.QueueDeclare().QueueName;

Bindings

我们已经创建好了exchange和queue,它们之间的关系我们叫做binding. 用来告诉exchange发送messages到queue.

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

现在,在logs exchange上会把messages发到我们的queue。

Listing bindings
rabbitmqctl list_bindings

代码

这种fanout exchanges ,在发送时,会忽视routingKey的值。

EmitLog.cs(发送)

using System;using RabbitMQ.Client;using System.Text;
class EmitLog
{
public 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"); //声明exchange var message = GetMessage(args);
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "logs", //发送到logs exchange
routingKey: "",
basicProperties: null,
body: body);
Console.WriteLine(" [x] Sent {0}", message);
} Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
} private static string GetMessage(string[] args)
{
return ((args.Length > )
? string.Join(" ", args)
: "info: Hello World!");
}
}

不允许发送到一个不存在的exchange.

如果没有queue绑定到exchange,messages将会丢失。如果没有consumer正在监听,我们可以安全的丢弃这些message.

ReceiveLogs.cs

using System;using RabbitMQ.Client;using RabbitMQ.Client.Events;using System.Text;
class ReceiveLogs
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using(var connection = factory.CreateConnection())
using(var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: "logs", type: "fanout"); //声明exchange var queueName = channel.QueueDeclare().QueueName; //获得随机queue name
channel.QueueBind(queue: queueName, //定义queue和exchange的关系
exchange: "logs",
routingKey: ""); Console.WriteLine(" [*] Waiting for logs."); var consumer = new EventingBasicConsumer(channel); //回调
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] {0}", message);
};
channel.BasicConsume(queue: queueName,
autoAck: true,
consumer: consumer); Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}

参考网址:

https://www.rabbitmq.com/tutorials/tutorial-three-dotnet.html

RabbitMQ学习之Publish/Subscribe(3)的更多相关文章

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

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

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

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

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

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

  4. 【RabbitMQ】Publish/Subscribe

    Publish/Subscribe 在上一节我们创建了一个work queue.背后的设想为每个任务被分发给明确的消费者.这节内容我们将做一些完全不同的事情 -- 我们将发送一条消息给多个消费者.这种 ...

  5. RabbitMQ(三) -- Publish/Subscribe

    RabbitMQ(三) -- Publish/Subscribe `rabbitmq`支持一对多的模式,一般称为发布/订阅.也就是说,生产者产生一条消息后,`rabbitmq`会把该消息分发给所有的消 ...

  6. (转)RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

  7. RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

  8. RabbitMQ --- Publish/Subscribe(发布/订阅)

    目录 RabbitMQ --- Hello Mr.Tua RabbitMQ --- Work Queues(工作队列) 前言 在第二篇文章中介绍了 Work Queues(工作队列),它适用于把一个消 ...

  9. RabbitMQ 分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

随机推荐

  1. Python基础(二)--基本数据类型、格式化输出、基本运算符

    一.基本数据类型 1.数字类型 #int整型 定义:age=10 #age=int(10) 用于标识:年龄,等级,身份证号,qq号,个数 #float浮点型 定义:salary=3.1 #salary ...

  2. 《linux就该这么学》课堂笔记08 用户权限、特殊权限、隐藏权限、su、sudo

    1.文件的读.写.执行权限可以简写为 r w x,亦可分别用数字4.2.1来表示 2.文件的特殊权限 2.1.SUID是一种对二进制程序进行设置的特殊权限,可以让二进制程序的执行者临时拥有属主的权限( ...

  3. 十七、Python面向对象之继承

    在面向对象,继承是一个很重要的特性 子类与父类,子类是对父类的一种扩展,在父类的属性和方法上进行一些扩展 示例:没带继承   #定义一个带编号和状态的门的类 class Door(object): d ...

  4. MarkDown中如何加入上标和下标

    上标 使用<sup></sup>标签包裹的部分就是上标,例如:A<sup>T</sup> 显示效果就是 AT . 下标 使用<sub>< ...

  5. 杨巧丽 实验十四 团队项目评审&课程学习总结

    实验十四 团队项目评审&课程学习总结 项目 内容 这个作业属于哪个课程 (https://www.cnblogs.com/nwnu-daizh/) 这个作业的要求在哪里 (https://ww ...

  6. 【java】定时任务停止时间设置

    我的需求:每天9点至20点运行 解决办法:@Scheduled(cron = "0 * 9,10,11,12,13,14,15,16,17,18,19 * * ?") 解释:  逗 ...

  7. 配置Maven环境变量-Eclipse/Idea添加Maven

    1. 文件下载 官网下载地址:http://maven.apache.org/download.cgi 下方有我提供的下载链接. 由于下载缓慢,提供一份我的下载链接:https://www.lanzo ...

  8. Qt常用类——QWidget

    QWidget类是所有用户界面对象的基类. Widget是用户界面的基本单元:它从窗口系统接收鼠标,键盘和其他事件,并在屏幕上绘制自己. 每个Widget都是矩形的,它们按照Z-order进行排序.

  9. git: hook 修改提交信息

    git获取数字顺序版本号 因为git的版本使用的是hash值,不能很直观的看出那个版本,所以想找到一种方法,获取顺序的版本号,在网上找到了方法,可以获取顺序版本号 摘自:[使用bash从SVN和Git ...

  10. js 压缩图片(只缩小体积,不更改图片尺寸)

      1.情景展示 如上图所示,点击上传图片按钮,调用手机摄像头拍照功能. <input onchange="javascript:imgFun.uploadPicture();&quo ...