(本实例都是使用的Net的客户端,使用C#编写),说明,中文方括号【】表示名词。

在上一个教程中,我们改进了我们的日志记录系统。 没有使用只能够进行虚拟广播的【Fanout】交换机,而是使用了【Direct】类型的交换机,这样做就可以让我们有可能选择性地接收日志。

虽然使用【Direct】类型的【消息交换机】改进了我们的系统,但它仍然有限制 - 它不能基于多个标准进行路由选择。

在我们的日志记录系统中,我们可能不仅要根据严重性订阅日志,还可以基于发出日志的源进行订阅。 您可能会从syslog unix工具中了解这一概念,该工具根据严重性(info/warn/crit...)和设施(auth / cron / kern ...)路由日志。

这将给我们很大的灵活性 - 我们可能既想监听来自“cron”的重要错误,也可以监听“kern”的所有日志。

要在我们的日志记录系统中实现,我们需要了解一个更为复杂的topic类型的【消息交换机】。

1、Topic类型的【消息交换机】

发送到【Topic】类型【消息交换机】的消息不能有任意的routing_key - 它必须是由点分隔的单词列表。 这些词可以是任何东西,但通常它们指定与消息相关联的一些功能。 几个有效的路由关键字示例:“stock.usd.nyse”,“nyse.vmw”,“quick.orange.rabbit”。 路由关键字中可以有任意多的单词,最多可达255个字节。

绑定键也必须是相同的形式。【Topic】类型的【消息交换机】背后的逻辑类似于【Direct】类型的【消息交换机】 - 使用特定【路由键】发送的消息将被传递到与匹配的【绑定键】绑定的所有队列。 但是,【绑定键】有两个重要的特殊情况:

*(星)可以替代一个字。
     #(井号)可以替换零个或多个单词。

在一个例子中最简单的解释一下:
   

在这个例子中,我们将发送所有描述动物的消息。消息将使用由三个字(两个点)组成的【路由键】发送。【路由键】中的第一个字将描述速度,第二个颜色和第三个种类:“<speed>.<color>.<species>”。

我们创建了三个绑定:Q1绑定键“*.orange.*”和Q2是“*.*.rabbit”和“lazy.#”绑定。

这些【绑定键】所要表达意思可以总结为:

Q1对所有的橙色动物感兴趣。

Q2想听听有关兔子的一切,以及关于lazy动物的一切。

将【路由键】设置为“quick.orange.rabbit”的消息将传递给两个队列。消息“lazy.orange.elephant”也会发送他们那两个队列。另一方面,“quick.orange.fox”只会发送到第一个队列,而“lazy.brown.fox”只能发送到第二个队列。 “lazy.pink.rabbit”将被传递到第二个队列只有一次,即使它匹配两个绑定。 “quick.brown.fox”不匹配任何绑定,所以它将被丢弃。

如果我们违反约定并发送一个或四个字的消息,如“orange”或“quick.orange.male.rabbit”,会发生什么?那么这些消息将不会匹配任何绑定,并将丢失。

另一方面,“lazy.orange.male.rabbit”即使它有四个字,将匹配上一个绑定,并将被传递到第二个队列。

说明:【Topic】类型的【消息交换机】

此类型的【消息交换机】是强大的,可以像其他【消息交换机】一样行事。

当队列用“#”(哈希)【绑定键】绑定时,它将接收所有消息,而不管【路由键】,就像使用【Fanout】类型的【消息交换机】。

当特殊字符“*”(星号)和“#”(哈希)不用于绑定时,【Topic】类型的【消息交换机】将表现得像一个使用【Direct】类型的【消息交换机】。

2、代码整合

我们将在我们的日志记录系统中使用【Topic】类型【消息交换机】。 我们将从一个工作假设开始,日志的【路由键】将有两个单词组成:“<facility>.<severity>”。

代码与上一个教程几乎相同。

EmitLogTopic.cs的代码:

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

ReceiveLogsTopic.cs的代码:

 using System;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text; class ReceiveLogsTopic
{
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: "topic_logs", type: "topic");
var queueName = channel.QueueDeclare().QueueName; if(args.Length < )
{
Console.Error.WriteLine("Usage: {0} [binding_key...]",
Environment.GetCommandLineArgs()[]);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
Environment.ExitCode = ;
return;
} foreach(var bindingKey in args)
{
channel.QueueBind(queue: queueName,
exchange: "topic_logs",
routingKey: bindingKey);
} Console.WriteLine(" [*] Waiting for messages. To exit press CTRL+C"); 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();
}
}
}

3、运行以下示例:

收到所有的日志:

cd ReceiveLogsTopic
dotnet run“#”

从设备“kern”接收所有日志:

cd ReceiveLogsTopic
dotnet run “kern.*”

或者如果您只想听到关于“critical”日志的信息:

ReceiveLogsTopic.exe“* .critical”

您可以创建多个绑定:

cd ReceiveLogsTopic
dotnet run“kern.*”“*.critical”

并使用【路由键】“kern.critical”类型发出日志:

cd emitLogTopic
dotnet run“kern.critical”“A critial kernel error”

写这些程序很有趣。 请注意,代码不会对【路由键】或【绑定键】做任何假设,您可能希望使用两个以上的【路由键】参数进行操作。

今天就到此为止了,如果英文比较好的,可以查看原文,原文地址是:http://www.rabbitmq.com/tutorials/tutorial-five-dotnet.html

RabbitMQ系列教程之五:主题(Topic)的更多相关文章

  1. RabbitMQ系列教程之五:主题(Topic)(转载)

    RabbitMQ系列教程之五:主题(Topic) (本实例都是使用的Net的客户端,使用C#编写),说明,中文方括号[]表示名词. 在上一个教程中,我们改进了我们的日志记录系统. 没有使用只能够进行虚 ...

  2. RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe)(转载)

    RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe) (本教程是使用Net客户端,也就是针对微软技术平台的) 在前一个教程中,我们创建了一个工作队列.工作队列背后的假设是每个 ...

  3. RabbitMQ系列教程之七:RabbitMQ的 C# 客户端 API 的简介(转载)

    RabbitMQ系列教程之七:RabbitMQ的 C# 客户端 API 的简介 今天这篇博文是我翻译的RabbitMQ的最后一篇文章了,介绍一下RabbitMQ的C#开发的接口.好了,言归正传吧. N ...

  4. RabbitMQ系列教程之六:远程过程调用(RPC)(转载)

    RabbitMQ系列教程之六:远程过程调用(RPC) 远程过程调用(Remote Proceddure call[RPC]) (本实例都是使用的Net的客户端,使用C#编写) 在第二个教程中,我们学习 ...

  5. RabbitMQ系列教程之四:路由(Routing)(转载)

    RabbitMQ系列教程之四:路由(Routing) (使用Net客户端) 在上一个教程中,我们构建了一个简单的日志系统,我们能够向许多消息接受者广播发送日志消息. 在本教程中,我们将为其添加一项功能 ...

  6. RabbitMQ系列教程之一:我们从最简单的事情开始!Hello World(转载)

    RabbitMQ系列教程之一:我们从最简单的事情开始!Hello World 一.简介 RabbitMQ是一个消息的代理器,用于接收和发送消息,你可以这样想,他就是一个邮局,当您把需要寄送的邮件投递到 ...

  7. 2.rabbitmq 系列教程

    rabbitmq系列教程-文章[转] 视频分享: 链接:https://pan.baidu.com/s/1s_Qr2A1o0s8Ru0exK62jqg 提取码:eb68

  8. RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe)

    (本教程是使用Net客户端,也就是针对微软技术平台的)   在前一个教程中,我们创建了一个工作队列.工作队列背后的假设是每个任务会被交付给一个[工人].在这一部分我们将做一些完全不同的事情--我们将向 ...

  9. rabbitmq系列五 之主题交换机

    1.主题 在前面的例子中,我们对日志系统进行了改进.使用了direct交换机代替了fanout交换机,从只能盲目的广播消息改进为有可能选择性的接收日志. 尽管直接交换机能够改善我们的日志系统,但是它也 ...

随机推荐

  1. Unity使用Mono.Xml代替System.Xml 测试

    测试环境 操作系统:Windows8.1 开发工具:Unity5.5.2 1.新建一个测试项目,观测引用System.Xml与Mono.Xml解析文件正确性,与打包后APK体积大小. 2.Mono.X ...

  2. CountDownLatch, CyclicBarrier and Semaphore

    Reference: [1] http://shazsterblog.blogspot.co.uk/2011/12/comparison-of-countdownlatch.html CountDow ...

  3. Java类加载器详解

    title: Java类加载器详解date: 2015-10-20 18:16:52tags: JVM--- ## JVM三种类型的类加载器- 我们首先看一下JVM预定义的三种类型类加载器,当一个 J ...

  4. javascript基础-事件1

    原理 事件分两种.第一种浏览器事件,由浏览器抛出事件,它是人机交互的基础:第二种自定义事件,由程序员抛出事件,它是模拟事件流程.两者都是为了完成数据的传递. 浏览器事件 机制 冒泡和捕获两种机制.因I ...

  5. OpenGL判断一个点是否可见

    关于OpenGL中判断一个点是否可见,可以分成两种情况讨论:点在2D空间中和3D空间中的时候.并且"在2D空间中"可以看作"在3D空间中"的特殊情况. 温馨提示 ...

  6. Java文件流应用:剪切文件

    剪切的实际操作是: 第一步,先复制文件到指定位置, 第二步,删除原文件,这样就实现了剪切 与复制文件相比,多了一步删除文件 注意:删除文件必须在流关闭后,才能删除,否则,删除不了. 实例代码 pack ...

  7. Unity应用架构设计(11)——一个网络层的构建

    对于客户端应用程序,免不了和远程服务打交道.设计一个良好的『服务层』能帮我们规范和分离业务代码,提高生产效率.服务层最核心的模块一定是怎样发送请求,虽然Mono提供了很多C#网络请求类,诸如WebCl ...

  8. jQuery链式操作如何返回上一级DOM

    有时候我们在链式操作的时候,选择到了其他的DOM进行操作,如何再返回先前的dom呢,有一下几个方法,end(); addBack(); add(); 使用形式 $("#divFather&q ...

  9. openvpn实现内网 映射到 外网

    openvpn实现内网 映射到 外网 场景介绍: 机器介绍 本地一台Ubuntu服务器A , 处于内网中 , 无外网IP 外网一台Ubuntu服务器B , 外网地址139.199.4.205 目标 : ...

  10. Thinkphp 3.0-3.1版代码执行漏洞

    近日360库带计划中播报的ThinkPHP扩展类库的漏洞已经查明原因:系官方扩展模式中的Lite精简模式中存在可能的漏洞(原先核心更新安全的时候 并没有更新模式扩展部分,现已更新).对于使用标准模式或 ...