C#使用RabbitMQ-5_主题模式(主题交换机)

news/2024/6/17 8:35:56 标签: c#, rabbitmq, 消息队列, 主题模式

简介

主题模式允许发送者根据主题发布消息,而订阅者可以订阅特定的主题

主题模式中,生产者发送的消息被发送到一个交换机(Exchange),该交换机根据消息的路由键(Routing Key)和绑定(Binding)规则将消息路由到一个或多个队列。消费者随后从队列中接收并消费这些消息。以下是主题模式的一些关键要点:

  1. 路由键的设计:路由键是由点(.)分隔的字符串,例如 "stock.usd.nyse"。这些字符串通常定义了消息的某些属性或分类。
  2. 通配符的使用:队列绑定时可以使用通配符 "*" 和 "#"。其中,星号可以替代一个单词,井号可以替代零个或多个单词。这增加了灵活性,允许使用模糊匹配来定义哪个队列应该接收具有特定路由键的消息。
  3. 消息的路由过程:当消息到达交换机时,交换机会查找所有绑定的队列,检查它们的绑定键,并确定哪些队列的绑定键与消息的路由键相匹配。匹配成功的队列会接收到消息。
  4. 灵活性和复杂性:与直接模式相比,主题模式提供了更大的灵活性,因为它允许基于多个标准进行路由。然而,这种灵活性也带来了额外的复杂性,因为需要正确设计路由键和绑定键以实现期望的路由行为。
  5. 消息的丢失风险:如果没有任何队列的绑定键与消息的路由键匹配,那么消息将会丢失。因此,正确配置交换机、队列的绑定以及路由键非常重要。

通配符

主题模式中的通配符其实就像我们平时写的正则表达式,比如在消费者中使用 "stock.#" 作为绑定键,那么那么绑定键 "stock.#" 的消费者将匹配到所有以 "stock" 开头的路由键,不论后面跟随什么单词。如"stock.usd.nyse"、"stock.eur.frankfurt" 还是 "stock.jpy.tokyo",只要是以 "stock" 开头的消息都会被该队列接收。

  • 星号(*):星号可以代替路由键中的一个单词。例如,如果有一个路由键为 "stock.usd.nyse" 的消息,那么绑定键 "stock.*.nyse" 或 "stock.usd.#" 都可以匹配到这个消息。星号可以匹配零个或多个单词,但不会跨越点(.)进行匹配。
  • 井号(#):井号可以代替路由键中的零个或多个单词,且可以跨越点进行匹配。这意味着,如果有一个路由键为 "stock.usd.nyse" 的消息,那么绑定键 "stock.#" 将匹配到所有以 "stock" 开头的路由键,不论后面跟随什么单词。

生产者

在之前的模式中,我们使用的都是路由键RoutingKey,而主题模式中的是绑定键 BindingKey。主题模式可以看作是一种特殊的路由模式,它允许更复杂的路由策略,通过使用通配符 "*" 和 "#" 来实现模糊匹配。从而实现处理更加复杂的消息路由需求。

RoutingKey 主要用于生产者发布消息时定义消息的路由路径,而 BindingKey 用于定义交换机与队列之间的绑定关系。

class MyClass
{
    public static void Main(string[] args)
    {
        var factory = new ConnectionFactory();
        factory.HostName = "localhost"; //RabbitMQ服务在本地运行
        factory.UserName = "guest"; //用户名
        factory.Password = "guest"; //密码

        //创建连接
        using (var connection = factory.CreateConnection())
        {
            //创建通道
            using (var channel = connection.CreateModel())
            {
                //声明了一个主题交换机(topic),命名为"hello"
                channel.ExchangeDeclare("hello", "topic");

                Console.WriteLine("生产者:请输入绑定key");
                var bindingKey = Console.ReadLine();

                string msg;
                Console.WriteLine("请输入要发送的消息内容:");
                while (!string.IsNullOrEmpty(msg = Console.ReadLine()))
                {
                    var body = Encoding.UTF8.GetBytes(msg);

                    channel.BasicPublish("hello", bindingKey, null, body); //开始传递
                    Console.WriteLine("已发送: {0}", msg);
                }
            }
        }
    }
}

消费者

class MyClass
{
    static void Main(string[] args)
    {
        //创建连接工厂
        var factory = new ConnectionFactory();
        factory.HostName = "localhost";
        factory.UserName = "guest";
        factory.Password = "guest";
        //创建连接
        using (var connection = factory.CreateConnection())
        {
            //创建通道
            using (var channel = connection.CreateModel())
            {
                //声明了一个交换机
                channel.ExchangeDeclare("hello", "topic");

                //声明一个新的队列,并将这个队列的名称赋值给变量 queueName
                var queueName = channel.QueueDeclare().QueueName;

                //从控制台获取一个绑定键
                Console.WriteLine("消费者:请输入BindingKey");
                var bindingKey = Console.ReadLine();

                channel.QueueBind(queueName, "hello", bindingKey);

                //事件的基本消费者
                var consumer = new EventingBasicConsumer(channel);

                consumer.Received += (model, ea) =>
                {
                    var body = ea.Body.ToArray();
                    var message = Encoding.UTF8.GetString(body);

                    Thread.Sleep(1000);

                    Console.WriteLine("已接收: {0}", message);
                };

                channel.BasicConsume(queueName, true, consumer);
                Console.ReadKey();
            }
        }
    }
}

演示

还是老样子,我们将生产者和消费者都发布打包,分别运行三次,然后生产者分别发送一条消息,如下图。

# 用于匹配多个单词。因此com.#三条消息都收到了。

* 用于匹配一个单词,因为有两个生产者的第三个单词是2,所以*.*.2的消费者收到了两条消息。

而只有一个生产者的第二个单词是B,所以*.B.*的消费者只收到了一条消息


http://www.niftyadmin.cn/n/5365807.html

相关文章

C++泛型编程:类模板(下)

类模板与继承&#xff1a; 需要指定模板参数的类型 template <class T> class Base { public:T m; }; class Son :public Base<int> { }; template <typename T1,typename T2> class Son2 :public Base<T2> { public:Son2(){cout << "T1的…

探索设计模式的魅力:外观模式简化术-隐藏复杂性,提供简洁接口的设计秘密

设计模式专栏&#xff1a;http://t.csdnimg.cn/U54zu 目录 引言&#xff1a;探索简化之路 一、起源和演变 二、场景案例分析 2.1 不用模式实现&#xff1a;用一坨坨代码实现 2.2 问题 2.3 外观模式重构代码 定义 界面 接口 利用外观模式解决问题步骤 外观模式结构和说明 重构…

kafka-splunk数据通路实践

目的&#xff1a; 鉴于目前网络上没有完整的kafka数据投递至splunk教程&#xff0c;通过本文操作步骤&#xff0c;您将实现kafka数据投递至splunk日志系统 实现思路&#xff1a; 创建kafka集群部署splunk&#xff0c;设置HTTP事件收集器部署connector服务创建connector任务&a…

判断字符串是否包含正则表达式默认的特殊字符c++

判断字符串是否包含正则表达式默认的特殊字符 业务描述&#xff1a; 上层配置的字符列表中&#xff0c;既有准确的字符串&#xff0c;又有可以进行正则匹配的字符串&#xff0c;这时候需要区分出来那些是正则匹配的字符串。 思路: 判断字符串中&#xff0c;是否存在正则表达…

【已解决】pt文件转onnx后再转rknn时得到推理图片出现大量锚框变花屏

前言 环境介绍&#xff1a; 1.编译环境 Ubuntu 18.04.5 LTS 2.RKNN版本 py3.8-rknn2-1.4.0 3.单板 迅为itop-3568开发板 一、现象 采用yolov5训练并将pt转换为onnx&#xff0c;再将onnx采用py3.8-rknn2-1.4.0推理转换为rknn&#xff0c;rknn模型能正常转换&#xff0c;…

音视频数字化(音频数字化)

在音视频领域,人们始终追求无限还原现场效果,因此音频越逼真越好,视频越清晰越好。之所以我们需要将音视频信号由模拟转为数字,目的是在录制、存储、编辑、复制、回放等环节的不失真,尽量保持原有细节,不因以上操作,导致音画的质量下降。 为此,视频系统分辨率越来越高,…

MATLAB频域分析(附完整代码)

1. MATLAB进行频域分析举例 以下是一个使用MATLAB进行频域分析的例子。在这个例子中&#xff0c;我们将生成一个含有两个不同频率分量的信号&#xff0c;然后使用快速傅里叶变换&#xff08;FFT&#xff09;来分析其频域特性。 main.m文件 clc;close all;clear all;warning of…

【DB2】—— 一次关于db2 sqlcode -420 22018的记录

情况描述 在DB2 10.5数据库中执行以下SQL语句&#xff1a; SELECT * FROM aa WHERE aa.ivc_typ IN (213,123,12334,345)其中aa.ivc_typ列的类型为VARCHAR(10) 关于执行会发生以下情况 类型转换&#xff1a;SQL引擎会尝试把IN列表中的整数常量转换为VARCHAR(10)类型&#xf…