绑定( Bindings)

 

之前的文章中我们已经创建过bindings,代码如下:

 

      channel.QueueBind(queue: queueName, exchange: EXCHANGE_NAME, routingKey: ROUTING_KEY, arguments: null);

 

绑定(bindings)是指交换机(exchange)与队列(queue)之间的关系。可以简单的理解为:队列(queue)对所绑定的交换机(exchange)上的消息感兴趣,交换机(exchange)要把它接收到的消息推送到队列(queue)中。

绑定的时候需要带上一个额外的参数routingKey,为避免与BasicPublish中的路由键(routing key)参数混淆,我们称之为绑定键(binding key),以下是如何创建一个绑定。

 

    channel.QueueBind(queue: queue, exchange: EXCHANGE_NAME, routingKey: "error", arguments: null);

 

注意:

  • 参数routingKey为空时,也是一个绑定键
  • 绑定键的意义依赖于exchange type。如:如果exchange type 为 fanout 时,绑定键没有任何意义。

 

直连交换机(direct exchange)

 

在之前的发布订阅中我们已经讲到直连交换机,我们了解到直连交换机的工作方式为——交换机(exchange)会对绑定键(binding key)与 路由键(routing key)进行精确匹配,然后将消息发送到能够匹配成功的队列中。

下图能够很好的描述整个场景:

在这个场景中,可以看出直连交换机X和队列(Q1与Q2)进行了绑定。Q1队列使用orange为绑定键(binding key),Q2有两个绑定,分别以black和green作为绑定键(binding key)。

这样以来,当路由键为orange的消息发送到交换机,就会被路由到队列Q1,路由键为black和green的下拍戏就会被路由到Q2,其它的消息将会被丢弃。

 

多重绑定(multiple bindings)

 

多重绑定即使用一个绑定键(binding key)绑定到多个队列,这是完全合法的,而且每个队列都能得到完全相同的信息。

 

示例

接下来我们就使用direct exchange完善之前的日志功能

1.日志级别为error的日志保存的到txt文件中

2.日志级别为log的日志输出到控制台面板

3.输出所有的日志到控制台面板

 

生产者 RoutingProducer.cs

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using RabbitMQ.Client;

using System.Threading;

 

namespace RabbitMQProducer

{

    public class RoutingProducer

    {

        const string EXCHANGE_NAME = "ROUTING_EXCHANGE";

        static readonly List<string> LEVELS = new List<string>() { "error", "log" };

        public static void Send()

        {

 

            ConnectionFactory factory = new ConnectionFactory() { HostName = "localhost" };

            using (IConnection connection = factory.CreateConnection())

            {

                using (IModel channel = connection.CreateModel())

                {

 

                    //创建交换机类型为 direct 的交换机

                    channel.ExchangeDeclare(exchange: EXCHANGE_NAME, type: ExchangeType.Direct);

                    for (int i = 0; i < 20; i++)

                    {

                        Thread.Sleep(100);

                        string level = GetLevels();

                        string message = $"日志信息:{i}——日志等级:{level}";

 

                        //发送消息至之前创建的交换机,并设置路由键为
日志级别

                        channel.BasicPublish(exchange: EXCHANGE_NAME, routingKey: level, basicProperties: null, body: Encoding.UTF8.GetBytes(message));

                        Console.WriteLine(message);

                    }

 

                    Console.WriteLine(" Press [enter] to exit.");

                    Console.ReadLine();

                }

            }

        }

 

        private static string GetLevels()

        {

            return LEVELS[new Random().Next(0, 2)];

        }

    }

}

 

消费者 RoutingConsumer.cs

 

using RabbitMQ.Client;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using RabbitMQ.Client.Events;

using System.IO;

namespace RabbitMQConsumer

{

    public class RoutingConsumer

    {

        const string EXCHANGE_NAME = "ROUTING_EXCHANGE";

        /// <summary>

        /// 是否使用多重绑定将所有日志级别消息输出到控制台

        /// 默认只是输出日志级别为log的内容到控制台

        /// </summary>

        /// <param name="all"></param>

        public static void Log(bool all = false)

        {

            var factory = new ConnectionFactory()

            {

                HostName = "127.0.0.1"

            };

            using (var connection = factory.CreateConnection())

            {

                using (var channel = connection.CreateModel())

                {

                    channel.ExchangeDeclare(exchange: EXCHANGE_NAME, type: ExchangeType.Direct);

                    //每次运行consumer客户端都创建一个新的queue,并且绑定到对应的exchange,这样使每次发送消息到exchange时就能把消息由exchange传递到所绑定的queue

                    QueueDeclareOk queue = channel.QueueDeclare();

                    string queueName = queue.QueueName;

                    channel.QueueBind(queue: queueName, exchange: EXCHANGE_NAME, routingKey: "log", arguments: null);

                    if (all)

                    {

                        channel.QueueBind(queue: queueName, exchange: EXCHANGE_NAME, routingKey: "error", arguments: null);

                    }

                    EventingBasicConsumer consumer = new EventingBasicConsumer(channel);

                    consumer.Received += (sender, e) =>

                    {

                        string message = Encoding.UTF8.GetString(e.Body);

                        Console.WriteLine($"LOG——日志信息:{message}");

                    };

                    channel.BasicConsume(queueName, noAck: true, consumer: consumer);

                    Console.WriteLine(" Press [enter] to exit.");

                    Console.ReadLine();

                }

            }

        }

        public static void Error()

        {

            var factory = new ConnectionFactory() { HostName = "127.0.0.1" };

            using (IConnection connection = factory.CreateConnection())

            {

                using (IModel channel = connection.CreateModel())

                {

                    //创建交换机类型为 direct 的交换机

                    channel.ExchangeDeclare(exchange: EXCHANGE_NAME, type: ExchangeType.Direct);

                    //创建一个未命名的新的消息队列,该队列名称有系统自动分配,并且为非持久化,在该队列没有订阅时自动删除的排它队列

                    QueueDeclareOk queue = channel.QueueDeclare();

                    string queueName = queue.QueueName;

                    //绑定exchange 与 queue 并设置路由键为日志级别error

                    channel.QueueBind(queue: queue, exchange: EXCHANGE_NAME, routingKey: "error", arguments: null);

                    EventingBasicConsumer consumer = new EventingBasicConsumer(channel);

                    consumer.Received += (sender, arg) =>

                    {

                        string message = Encoding.UTF8.GetString(arg.Body);

                        //写入日志到txt文件

                        using (StreamWriter writer = new StreamWriter(@"c:\log\log.txt", true, Encoding.UTF8))

                        {

                            writer.WriteLine(message);

                            writer.Close();

                        }

                    };

                    channel.BasicConsume(queue: queueName, noAck: true, consumer: consumer);

                }

            }

        }

    }

}

RabbitMQ入门教程——路由(Routing)的更多相关文章

  1. RabbitMQ入门:路由(Routing)

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

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

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

  3. RabbitMQ入门教程(六):路由选择Routing

    原文:RabbitMQ入门教程(六):路由选择Routing 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog. ...

  4. RabbitMQ入门教程(十):队列声明queueDeclare

    原文:RabbitMQ入门教程(十):队列声明queueDeclare 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https:// ...

  5. RabbitMQ入门教程(七):主题交换机Topics

    原文:RabbitMQ入门教程(七):主题交换机Topics 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog. ...

  6. RabbitMQ入门教程(三):Hello World

    原文:RabbitMQ入门教程(三):Hello World 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog. ...

  7. RabbitMQ入门教程(二):简介和基本概念

    原文:RabbitMQ入门教程(二):简介和基本概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn ...

  8. RabbitMQ入门教程(十七):消息队列的应用场景和常见的消息队列之间的比较

    原文:RabbitMQ入门教程(十七):消息队列的应用场景和常见的消息队列之间的比较 分享一个朋友的人工智能教程.比较通俗易懂,风趣幽默,感兴趣的朋友可以去看看. 这是网上的一篇教程写的很好,不知原作 ...

  9. RabbitMQ入门教程(十四):RabbitMQ单机集群搭建

    原文:RabbitMQ入门教程(十四):RabbitMQ单机集群搭建 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://b ...

随机推荐

  1. [HIMCM暑期班]第2课:建模

    第二节课从最简单的模型开始入手:七桥问题. 首先,先去wikipedia上了解一些有关七桥问题的背景知识.http://en.wikipedia.org/wiki/Seven_Bridges_of_K ...

  2. cmd 下通过NTML代理访问Maven 库

    公司用web代理,NTLM验证的,这样在普通CMD下无法使用mvn命令访问网上的maven库,使用CNTLM工具解决. 下载CNTLM工具,安装,修改安装路径下的cntlm.ini,改成实际的ntlm ...

  3. IOS UIView 02- 深入理解 Scroll Views

    注:本人是翻译过来,并且加上本人的一点见解. 前言 可能你很难相信 UIScrollView 和一个标准的 UIView 差异并不大,scroll view 确实会多出一些方法,但这些方法只是和 UI ...

  4. H5 调用摄像头

    WebRTC(Web Real-Time Communication,网页实时通信),是一个支持网页浏览器进行实时语音对话或视频对话的API. 1.getUserMedia 要播放摄像头的影像,首先需 ...

  5. PHP面向对象07_PDO

    oop007复习 2014-9-4 9:42:28 摘要: 1.pdo的作用 2.pdo的安装 3.pdo连接属性设置 4.pdo对象和PDOStatement对象 5.pdo预处理 6.pdo事务机 ...

  6. Java程序员的日常 —— 多进程开发

    最近再弄进程管理相关的工作,因此必要的就涉及到各种系统下关于进程的管理. 这里简单的介绍下: 如何在Java中执行命令 在windows下肯定是dos命令了,而在linux则为shell命令.执行的方 ...

  7. Angularjs学习---ubuntu12.04中karma安装配置中常见的问题总结

    karma启动时出现了很多问题: 1.安装karma前提条件 安装karma首先要安装nodejs,npm然后才可以安装karma.nodejs,npm的安装过程可以参考文章:Angularjs学习- ...

  8. Thinking in java中关于Exception的一道面试题.

    今天看到Thinking in Java中一个关于Exception的例子:最后看到有一篇总结的比较好的文章, 这里拿来记录下, 文章地址是:http://blog.csdn.net/salerzha ...

  9. paip.lucene 4.3 中文语义搜索最佳实践

    paip.lucene 4.3 中文语义搜索最佳实践 首先一个问题是要不要使用lucene 自带的分词器...我觉得最好不使用哪自带的分词器.效果还凑火,就是不好控制... 先使用ik,ict,mms ...

  10. JS util

    一.返回上一页(history) 发觉有两种用法: 1.javascript:history.back(-1); 2.javascript:history.go(-1); 它们俩的区别是: histo ...