前一篇文章中我们构建了一个简单的日志系统,我们可以向多个接受者广播消息。

在这篇文章我,我们将要添加一些功能使得针对部分消息的接受成为可能,例如我们只对错误的消息进行磁盘记录,同时又可以把所有的消息打印到屏幕上。

绑定

在之前的案例中,我们已经创建了一个绑定,可以重新调用如下的代码:

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

绑定是交换机和队列之间的关系,可以简单的理解为队列对该交换机上的消息感兴趣。

绑定可以设定参数routingKey,为了避免和BasicPublish 方法的参数混淆,我们暂且称之为binding key,下面是我们创建一个带有指定binding key的绑定:

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

Direct exchange

我们之前的日志系统,把接受到的消息广播给所有的接受者,我们将要扩展它使得其能够根据消息的级别来过滤发送消息,例如我们想让记录日志的接受者仅仅接受严重性级别的错误消息,而不用在警告和信息级别的消息上浪费磁盘空间。

fanout没有办法提供给我们这样的灵活性,它只能对接受到的消息进行直接广播,而不去关心 routing key.

这里我们使用direct类型的交换机去代替,direct类型的交换机的实现思想非常简单--消息将会被发送到其Binding key 和消息的routing key 完全匹配的队列上。

为了说明这个问题,考虑下面的设定:

在这个交换机上绑定了两个队列,第一个队列绑定的bingding key 为"orange",第二个队列绑定了两个binding key,一个是"black",另外一个是"green",在这样的配置下,如果一个带有routing key为"orange"的消息,竟会被路由到队列Q1上,而带有routing key为"black" 或 "green"的消息将会被路由到队列Q2上。

多绑定

使用一个routing key 绑定多个队列完全是合法的,在我们案例中我们可以在 路由X 和 队列Q1,Q2中同时添加一个binding key为"black"的绑定,在这种情况下路由 X 将会像 fanout交换机一样帮匹配到的消息发送给所有的接受者:路由会把routing key 为"black"的消息发送给Q1和Q2。

嵌入日志

我们使用这种模式来构建我们的日志系统,代替fanout我们将会把我们的消息发送到direct类型的交换机,我们把日志级别作为路由的rouing key,这样接受者就可以根据日志级别选择接受其感兴趣的日志。

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

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

然后我们准备发送消息:

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

我们简单的假设 severity 分为以下几种:"info","warning","error".

订阅

接受消息和之前的一样,唯一的区别就是我们将会为我们感兴趣的每一个级别的消息新建绑定:

var queueName = channel.QueueDeclare().QueueName;

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

汇总

EmitLogDirect.cs:

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:

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

发送一个Error消息, 控制台输入 EmitLogDirect.exe error "Run. Run. Or it will explode."

RabbitMQ 原文译04--路由的更多相关文章

  1. RabbitMQ 原文译1.2--"Hello Word"

    本系列文章均来自官网原文,属于个人翻译,如有雷同,权当个人归档,忽喷. .NET/C# RabbitMQ 客户端下载地址:https://github.com/rabbitmq/rabbitmq-do ...

  2. RabbitMQ 原文译1.1--HelloWord

    本系列文章均来自官网原文,属于个人翻译,如有雷同,权当个人归档,忽喷. RabitMQ 是一个消息中间件,其实就是从消息生产者那里接受消息,然后发送给消息消费者.在这个传输过程中,可以定义一些缓存,持 ...

  3. RabbitMQ 原文译03--发布和订阅

    发布/订阅 在之前的案例中我们创建了一个工作队列,这个工作队列的实现思想就是一个把每一个任务平均分配给每一个执行者,在这个篇文章我们会做一些不一样的东西,把一个消息发送给多个消费者,这种模式就被称作& ...

  4. RabbitMQ 原文译02--工作队列

    工作队列: 在上一篇文章中我们我们创建程序发送和接受命名队列中的消息,在这篇文章我会创建一个工作队列,用来把耗时的操作分配给多个执行者. 工作队列(任务队列)的主要实现思想是避免马上执行资源密集型的任 ...

  5. RabbitMQ 原文译06--Remote procedure call(RPC)

    在第三篇文章中, 我们学习了怎么使用队列在多了消息消费者当中进行耗时任务轮询. 但是如果我们想要在远程电脑上运行一个方法,然后等待其执行结果,这就是一个不同的场景,这种就是我们一般讲的RPC(远程过程 ...

  6. RabbitMQ 原文译05--Topics

    在之前的系统中,我们改进了我们的日志系统,我们使用direct 交换机代替fanout交换机,可以实现选择性的接受日志. 虽然使用direct 交换机改进了我们的系统,但是对于多种条件的判断,依然存在 ...

  7. RabbitMQ六种队列模式-路由模式

    前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式 [本文]RabbitMQ六种队列模式-主 ...

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

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

  9. RabbitMQ的工作队列和路由

    工作队列:Working Queue   工作队列这个概念与简单的发送/接收消息的区别就是:接收方接收到消息后,可能需要花费更长的时间来处理消息,这个过程就叫一个Work/Task.   几个概念 分 ...

随机推荐

  1. Linux PHP实现仿百度文库预览功能

    1.安装openoffice: tar zxvf OOo_3.3.0_Linux_x86-64_install-rpm-wJRE_zh-CN.tar.gzcd RPEMrpm -ivh *.rpm安装 ...

  2. 将树莓派Raspberry Pi设置为无线路由器(WiFi热点AP,RTL8188CUS芯片)

    http://wangye.org/blog/archives/845/ 最近又开始折腾起Raspberry Pi来了,因为某处上网需要锐捷拨号,于是我就想能不能让我的树莓派代劳,当然首先要将其改造为 ...

  3. TCP/IP协议详解内容总结

    TCP/IP协议 TCP/IP不是一个协议,而是一个协议族的统称.里面包括IP协议.IMCP协议.TCP协议. TCP/IP分层:   这里有几个需要注意的知识点: 互联网地址:也就是IP地址,一般为 ...

  4. Android实例-如何将文件打包到安装文件(XE8+小米2)

    结果: 1.文件名支持英文字母.数字,不支持中文,大小写敏感. 2.文件最好放在根目录下,或是子目录下,如果放在根目外,根目录改名后,找不到文件. 3.打开Project->Deployment ...

  5. A Tour of Go Buffered Channels

    Channels can be buffered. Provide the buffer length as the second argument to make to initialize a b ...

  6. [iOS基础控件 - 6.8] 各种数据类型的@property属性

    A.内存管理 NSString: copy 基本数据类型.结构体(int, CGFloat, BOOL, CGRect等):assign 对象(如自定义model类型.NSArray.NSDictio ...

  7. Sublime Text2 中Emmet(之前叫Zencoding)插件安装以及使用

    一.添加插件之前先 下载Package Control 按 Ctrl+`(就是~这个键) 复制下面的代码 确认 重新启动sublime text2 import urllib2,os;pf='Pack ...

  8. 325. Maximum Size Subarray Sum Equals k

    最后更新 二刷 木有头绪啊.. 看答案明白了. 用的是two sum的思路. 比如最终找到一个区间,[i,j]满足sum = k,这个去见可以看做是 [0,j]的sum 减去 [0,i]的Sum. 维 ...

  9. 【Stage3D学习笔记续】山寨Starling(十二):总结和一些没提到的东西

    我们的山寨Starling到这里就告一段落了,不得不说这是一个非常优秀的2D框架,他的设计和架构为后来的许多框架都提供了很好的参考,比如现在正在崛起的Egret,我们的一番解读也只是窥见了Starli ...

  10. React-native 中的触摸响应功能

    我们在做APP的时候,与桌面应用系统不同的是触摸响应. web页面对触摸响应的支持和原生的APP有着很大的差异. 基本用法 componentWillMount: function() { this. ...