在前一篇中,我们构建了一个简单的日志系统,我们已经能够广播消息到许多的接收者。在这一篇中,我们希望增加一个特性,让订阅消息的子集成为可能。例如,我们可以将重要的错误日志存放到日志文件(即,磁盘上面),同时将仍然所有的日志信息打印到控制台。

绑定

在前面的例子中我们已经创建过绑定,你应该还能记得下面的代码:

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

一个绑定是一个交换器和一个队列的关系,可以形象的解读为:这个队列对来自这个交换器的消息感兴趣。绑定可以拥有一个额外的参数:routingKey,为了避免和BasicPublish里面的routingKey混淆,我们称其为绑定关键字(binding Key),下面展示了如何通过一个绑定关键字创建一个绑定:

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

绑定关键字的意义依赖于交换器的类型,前面我们使用过的fanout类型的交换器,直接简单的忽略了它的绑定关键字的值。

Direct交换器

前一篇教程中的日志系统广播所有的消息到所有的消费者,我们希望扩展它能根据严重程度对消息进行过滤。例如,我们希望写日志到磁盘的程序能够只接收重要的错误,不要在“警告”、“信息”级别的日志身上浪费磁盘空间。

我们使用fanout类型的交换器,并不能带来很大的灵活性,它只能盲目的广播。作为替代,我们将使用direct类型的交换器,这种交换器背后的路由算法非常简单,消息发送到绑定关键字(binding Key)和消息的路由关键字(routing Key)完全匹配的队列。

为了帮助说明,设想下面的配置:

在这个设置中,我们看到direct类型的交换器X绑定了两个队列.第一个队列绑定关键字是orange;第二个队列有两个绑定,一个是black,另一个是green。在这样的配置中,发送到使用orange为路由关键字的消息将被路由到Q1,使用black或green为路由关键字的消息将被路由到队列Q2,其他消息将被销毁。

多绑定

使用同一个绑定关键字绑定多个队列是完全合法的,在我们的示例中我们可以在X和Q1中添加一个以black为绑定关键字的绑定。在这种情况下,direct类型的交换器会展现出fanout类型交换器的行为,并且会广播消息到所有满足条件的队列,发送到路由关键字为black的消息会发送到Q1和Q2.

发送日志

我们会为日志系统使用这种模式,将消息发送到direct类型而非fanout类型的交换器。我们将使用日志的严重等级来作为路由关键字,这样的话消息的接收程序就可以依据自己的需要选择不同的严重等级。首先让我们把注意力集中到发送日志上。

和往常一样,我们首先需要创建一个交换器:

 channel.ExchangeDeclare(exchange: "direct_logs", type: "direct");

接着我们准备好发送消息了:

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

为了简化问题,我们假设严重等级是‘info’、‘warning’、‘error’。

订阅

马上就可以像前面的教程中那样接收消息了,但是有一个不同点,我们要用自己感兴趣的所有日志严重程度分别创建一个绑定。

 var queueName = channel.QueueDeclare().QueueName;

 foreach(var severity in args)
{
channel.QueueBind(queue: queueName,
exchange: "direct_logs",
routingKey: severity);

组合在一起

EmitLogDirect.cs类的代码:

 using System;
using System.Linq;
using RabbitMQ.Client;
using System.Text; class EmitLogDirect
{
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: "direct_logs",
type: "direct"); var severity = (args.Length > ) ? args[] : "info";
var message = (args.Length > )
? string.Join(" ", args.Skip( ).ToArray())
: "Hello World!";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "direct_logs",
routingKey: severity,
basicProperties: null,
body: body);
Console.WriteLine(" [x] Sent '{0}':'{1}'", severity, message);
} Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}

ReceiveLogsDirect.cs的代码:

 using System;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text; class ReceiveLogsDirect
{
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: "direct_logs",
type: "direct");
var queueName = channel.QueueDeclare().QueueName; if(args.Length < )
{
Console.Error.WriteLine("Usage: {0} [info] [warning] [error]",
Environment.GetCommandLineArgs()[]);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
Environment.ExitCode = ;
return;
} foreach(var severity in args)
{
channel.QueueBind(queue: queueName,
exchange: "direct_logs",
routingKey: severity);
} Console.WriteLine(" [*] Waiting for messages."); var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
var routingKey = ea.RoutingKey;
Console.WriteLine(" [x] Received '{0}':'{1}'",
routingKey, message);
};
channel.BasicConsume(queue: queueName,
noAck: true,
consumer: consumer); Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}

像通常那样编译(编译建议见教程一)。

如果你只想保存严重等级为‘warning’、‘error’的日志到文件中,只需要打开控制台然后输入:

 $ ReceiveLogsDirect.exe warning error > logs_from_rabbit.log

如果你想在屏幕上看到所有的日志,打开另一个终端输入:

 $ ReceiveLogsDirect.exe info warning error
[*] Waiting for logs. To exit press CTRL+C

如果想发送‘error’级别的日志,举例来说,你只需要输入如下信息:

 $ EmitLogDirect.exe error "Run. Run. Or it will explode."
[x] Sent 'error':'Run. Run. Or it will explode.' 

进入教程五,了解如何基于模式(pattern)监听消息。

原文链接:http://www.rabbitmq.com/tutorials/tutorial-four-dotnet.html

【译】RabbitMQ:路由(Routing)的更多相关文章

  1. RabbitMQ官方中文入门教程(PHP版) 第四部分:路由(Routing)

    路由(Routing) 在前面的教程中,我们实现了一个简单的日志系统.可以把日志消息广播给多个接收者. 本篇教程中我们打算新增一个功能——使得它能够只订阅消息的一个字集.例如,我们只需要把严重的错误日 ...

  2. RabbitMQ学习总结 第五篇:路由Routing

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

  3. [译]RabbitMQ教程C#版 - 路由

    先决条件 本教程假定 RabbitMQ 已经安装,并运行在localhost标准端口(5672).如果你使用不同的主机.端口或证书,则需要调整连接设置. 从哪里获得帮助 如果您在阅读本教程时遇到困难, ...

  4. RabbitMQ 入门教程(PHP版) 第四部分:路由(Routing)

    路由(Routing) 在前面的第三部分教程中,我们实现了一个简单的日志系统.可以把日志消息广播给多个接收者. 本篇教程中我们打算新增一个功能——使得它能够只订阅消息的一个字集.例如,我们只需要把严重 ...

  5. asp.net MVC 5 路由 Routing

    ASP.NET MVC ,一个适用于WEB应用程序的经典模型 model-view-controller 模式.相对于web forms一个单一的整块,asp.net mvc是由连接在一起的各种代码层 ...

  6. AngularJS - 路由 routing 基础示例

    AngularJS 路由 routing 能够从页面的一个视图跳转到另外一个视图,对单页面应用来讲是至关重要的.当应用变得越来越复杂时,我们需要一个合理的方式来管理用户在使用过程中看到的界面.Angu ...

  7. [译]RabbitMQ教程C#版 - “Hello World”

    [译]RabbitMQ教程C#版 - “Hello World”   先决条件本教程假定RabbitMQ已经安装,并运行在localhost标准端口(5672).如果你使用不同的主机.端口或证书,则需 ...

  8. 路由(Routing)

    路由(Routing)  ASP.NET Core MVC 路由是建立在ASP.NET Core 路由的,一项强大的URL映射组件,它可以构建具有理解和搜索网址的应用程序.这使得我们可以自定义应用程序 ...

  9. RabbitMQ入门:路由(Routing)

    在上一篇博客<RabbitMQ入门:发布/订阅(Publish/Subscribe)>中,我们认识了fanout类型的exchange,它是一种通过广播方式发送消息的路由器,所有和exch ...

  10. RabbitMQ入门(4)——路由(Routing)

    这一篇我们将介绍如何订阅消息的一个子集.例如,我们只需要将日志中的error消息存储到日志文件中而将所有日志消息都在控制台打印出来. 绑定(Bindings) 在前面的例子中,我们创建了交换机和队列的 ...

随机推荐

  1. ios 设置声音和震动,单独控制

    一.今天项目中涉及了设置这快的声音震动和响铃,搞的头大,以前搞过,只是简单的调用系统的方法就可以实现,但是现在的公司要求,震动是震动,响铃是响铃,我看了微信,微信也是的分开的,做的很好,但是我就纳闷了 ...

  2. MySQL 基础语句

    MySQL 基础语句 多个知识点 ----------------------------------------------------------------------------------- ...

  3. javascript-with()方法

    1)简要说明         with 语句可以方便地用来引用某个特定对象中已有的属性,但是不能用来给对象添加属性.要给对象创建新的属性,必须明确地引用该对象. 2)语法格式  with(object ...

  4. Composer实现PHP中类的自动加载

    本篇博客承接上一篇,学习一下Composer实现的PHP的类的自动加载方式.首先说明一下,Composer是PHP针对PHP语言的第三方的依赖管理工具,将工程所用到的依赖文件包含在composer.j ...

  5. JS function document.onclick(){}报错Syntax error on token "function", delete this token

    JS function document.onclick(){}报错Syntax error on token "function", delete this token func ...

  6. TCP连接的三次握手和四次解散过程

    客户端和服务器在使用TCP连接传输数据的过程中,需要经过三次握手建立连接和四次握手断开连接操作. 具体如下图所示 上图描述了TCP连接从建立到断开的详细过程,以下就其中的具体报文细节展开讨论. 在TC ...

  7. 接口与继承ppt作业

    问:为什么子类的构造方法在运行之前,必须调用父类的构造方法?能不能反过来?为什么不能反过来? 答:子类拥有父的成员变量和成员方法,如果不调用,则从父类继承而来的成员变量和成员方法得不到正确的初始化.不 ...

  8. java网络流传输,中文乱码问题。

    最近需要从某个网页上抓取数据.一波三折. 1. 先要找到网站页面调用后台数据服务的url地址,但是本人对js不了解,花了不少时间在分析其网页源代码的js部分,试图寻找出调用数据的链接. 后来得知浏览器 ...

  9. Nginx内置变量以及日志格式变量参数详解

    $args #请求中的参数值 $query_string #同 $args $arg_NAME #GET请求中NAME的值 $is_args #如果请求中有参数,值为"?",否则为 ...

  10. Avalon接口协议

    Avalon接口协议 https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/manual/mnl_ava ...