【RabbitMQ 项目】服务端:路由交换模块

news2024/9/19 17:33:35

文章目录

  • 一.概念辨析
  • 二.编写思路
  • 三.代码实践

一.概念辨析

  1. 这个模块是干啥的?
    用户给服务器发送一条消息,消息中只指定了交换机,没有指定具体要发布到哪些队列。这个时候服务器模块就需要使用我们的路由交换模块,选择与之匹配的队列了
  2. 怎么匹配?
    一个交换机和一个绑定的队列是否匹配,取决于两个要素:
    具体如下:
  • DIRECT——直接交换:routinng_key 和 binding_key 相等则匹配成功
  • FANOUT——广播交换:不用做任何比较,直接匹配成功(注意前提是这个队列和交换机有绑定关系)
  • TOPIC——主题交换:只有 routing_key 和 binding_key“匹配”,交换机和队列才匹配成功
  1. routing_key 和 binding_key 构成
    routing_key:由若干个单词构成,单词之间用".“分开,单词由字母,数字和下划线构成
    binding_key:在 routing_key 的基础上多了两个通配符”*"和“#”,可以匹配一个单词,#可以匹配 0 个或多个单词
    规定
    和#只能单独存在,不能和其它字符一起组成一个单词,并且#附近不能再有通配符了,因为#已经可以匹配任意多个单词了,再加通配符是没有意义的

二.编写思路

本模块是一个纯算法模块,不管理数据,指向外提供一些静态方法,供服务器模块使用。

方法:

  1. 判断 binding_key 是否合法:当要新建一个 binding 时,服务器模块会先检查用户给的 binding_key 是否合法
    先遍历判断是否有不合法的字符,然后检查每个单词合法性,即不能通配符和普通字符混搭,最后检查#附近是否有通配符
  2. 判断 routing_key 是否合法:服务器模块检查用户发来的消息中的 routing_key 是否合法,如果这都不合法,那根本无法路由交换,选择与之匹配的队列了
    只需遍历判断是否有不合法字符即可
  3. 判断 routing_key 是否能和 binding_key 匹配
  • 直接交换:判断 routing_key 和 binding_key 是否相等
  • 广播交换:直接返回 true
  • 主题交换:两个数组的动态规划问题
    首先把 binding_key,routing_key 分割成一个个单词构成的单词的数组
    建一个 dp 表,dp[i][j]的含义是 binding 单词表的[0,i]部分,和 routing 单词表的[0, j]部分是否匹配
    dp[i][j]怎么填?考虑两个单词表的第 i 个单词和第 j 个单词
    分类讨论:
  1. 如果 binding 表和 routing 表最后一个单词相同,或者 binding 表最后是"*",那么最后一个单词就匹配上了,整体能否匹配取决于他们前面部分能否匹配,取决于 dp[i-1][j-1]的状态
    [i, j]这个格子的左上方如果为真,它就为真
  2. 如果 binding 表最后一个单词是#,接下来有三种做法:
    1. #与和 routing 表最后一个单词匹配,并且#消去,整体能否匹配取决于 dp[i-1][j-1]
    2. #和 routing 表最后一个单词匹配,但是#不消去,继续向前匹配,整体能否匹配取决于 dp[i][j-1]
    3. #不和最后一个单词匹配,但是#消去,相当于#匹配了 0 个单词,整体能否匹配去取决于 dp[i-1][j]
      所以[i,j]这个格子左上方,左方,上方,任何一个为真即为真

三.代码实践

Route.hpp:

#pragma once
#include "../common/Util.hpp"
#include "../common/Type.hpp"
namespace ns_route
{
    class Router
    {
    public:
        static bool isLegalRoutingKey(const std::string &routingKey)
        {
            // 只能有字母,数字和下划线
            for (auto ch : routingKey)
            {
                if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_' ||
                    (ch >= '0' && ch <= '9') || ch == '.')
                {
                    continue;
                }
                else
                {
                    return false;
                }
            }
            return true;
        }

        static bool isLegalBindingKey(const std::string &bindingKey)
        {
            // 先判断是否有非法字符
            for (auto ch : bindingKey)
            {
                if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_' || (ch >= '0' && ch <= '9') ||
                    ch == '*' || ch == '#' || ch == '.')
                {
                    continue;
                }
                else
                {
                    return false;
                }
            }

            // 检查每个单词是否合法:通配符只能单独存在
            std::vector<std::string> words;
            int wordNum = ns_util::StringUtil::split(bindingKey, ".", &words, ns_util::SepType::SPLITEASCHAR);
            for (const auto &word : words)
            {
                if (word.size() > 1 &&
                    (word.find('*', 0) != std::string::npos || word.find('#', 0) != std::string::npos))
                {
                    //LOG(INFO) << "单词不合法, bindingKey:" << bindingKey << ", word: " << word << endl;
                    return false;
                }
            }

            // 检查‘#’附近是否有通配符
            for (int i = 1; i < wordNum; i++)
            {
                if (words[i] == "#")
                {
                    if (words[i - 1] == "*" || words[i - 1] == "#")
                    {
                        //LOG(INFO) << "#附近有通配符, bindingKey: " << bindingKey << endl;
                        return false;
                    }
                }
            }

            return true;
        }

        static bool isMatched(const std::string &routingKey, const std::string &bindingKey, ns_data::ExchangeType type)
        {
            if (type == ns_data::ExchangeType::DIRECT)
            {
                return routingKey == bindingKey;
            }
            else if (type == ns_data::ExchangeType::FANOUT)
            {
                return true;
            }

            //主题交换
            std::vector<std::string> routingWords;
            std::vector<std::string> bindingWords;
            int m = ns_util::StringUtil::split(bindingKey, ".", &bindingWords, ns_util::SepType::SPLITEASCHAR);
            int n = ns_util::StringUtil::split(routingKey, ".", &routingWords, ns_util::SepType::SPLITEASCHAR);

            // dp[i]对[j]表示对于bindingKey和routingKey分割出来的单词表,前者[0,i]和后者[0,j]是否匹配
            std::vector<std::vector<bool>> dp(m + 1, std::vector<bool>(n + 1, false));
            dp[0][0] = true; // 当两者都为空时匹配成功

            // 如果bindingWords的第一个单词是“#”,要特殊处理
            if (bindingWords[0] == "#")
            {
                dp[1][0] = true;
            }
            // #后面不可能继续跟#,无需往后判断了

            for (int i = 1; i <= m; i++)
            {
                for (int j = 1; j <= n; j++)
                {
                    int x = i - 1;
                    int y = j - 1;
                    if (bindingWords[x] == "#")
                    {
                        // 考虑二者的最后一个单词:
                        // 1.#和routingWords[y]匹配,并且#消去了
                        // 2.#和routingWords[y]匹配,但#留下继续向前匹配
                        // 3.#不和routingWords[y]匹配,但#消去了
                        dp[i][j] = dp[i - 1][j - 1] || dp[i][j - 1] || dp[i - 1][j];
                    }
                    else // 普通单词或者“*”
                    {
                        if (bindingWords[x] == "*" || bindingWords[x] == routingWords[y])
                        {
                            dp[i][j] = dp[i - 1][j - 1];
                        }
                    }
                }
            } // end of for(int i)
            return dp[m][n];
        }
    };
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2146690.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

javascript-代码执行原理

js 是解释型语言 js 引擎执行流程 分为两个阶段: 语法分析执行阶段执行阶段涉及的数据结构: 调用栈。处理执行上下文和执行代码内存堆。给对象分配内存任务队列。暂存待执行的任务,分为宏任务队列和微任务队列语法分析 词法分析 > 语法分析 > 代码生成(字节码) …

封装svg图片

前言 项目中有大量svg图片&#xff0c;为了方便引入&#xff0c;所以对svg进行了处理 一、svg是什么&#xff1f; svg是可缩放矢量图形&#xff0c;是一种图片格式 二、使用步骤 1.创建icons文件夹 将icons文件夹放进src中&#xff0c;并创建一个svg文件夹和index.js&…

深入探索迭代器模式的原理与应用

&#x1f3af; 设计模式专栏&#xff0c;持续更新中 欢迎订阅&#xff1a;JAVA实现设计模式 &#x1f6e0;️ 希望小伙伴们一键三连&#xff0c;有问题私信都会回复&#xff0c;或者在评论区直接发言 迭代器模式 &#x1f4bb; 迭代器模式 (Iterator Pattern) 是一种行为设计模…

【LeetCode】每日一题 2024_9_19 最长的字母序连续子字符串的长度(字符串,双指针)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 题目&#xff1a;坐上公交的最晚时间 代码与解题思路 func longestContinuousSubstring(s string) (ans int) { // 题目要求&#xff1a; 最长 的 字母序连续子字符串 的长度// 双指针&#xff0c;start …

【学习笔记】线段树分裂

前言 有线段树合并就应该有线段树分裂。它是线段树合并的逆过程。具体的&#xff0c;你需要以权值线段树中第 k 小的数为分界线&#xff0c;把线段树分成两半。 算法流程 和线段树上二分类似。假设原来的线段树为 u&#xff0c;要分裂出线段树 v 记左子树的权值为 val。如果…

CodeMeter助力软件授权与IP保护,保障工业自动化与物联网安全

随着工业自动化的飞速发展&#xff0c;Hilscher的开放工业4.0联盟&#xff08;OI4&#xff09;旗舰店应运而生&#xff0c;将应用商店模式引入工业领域。凭借CodeMeter授权和加密技术的支持&#xff0c;该商店为工业用户提供了一个安全且开放的应用程序和解决方案平台。该平台不…

超声波清洗机哪个品牌好用又实惠?精选业内四款优质清洗机推荐

超声波清洗机作为一种创新的清洁解决方案&#xff0c;凭借其深入微观的清洁效能、简便的操作方式以及对物品的细腻呵护&#xff0c;正逐渐成为广受喜爱的清洁良品。不过&#xff0c;市面上品牌林立、型号多样&#xff0c;价格亦波动不一&#xff0c;这无疑为消费者选购时平添了…

ATT&CK靶机实战系列之vulnstack2

声明: 本文章只是用于网络安全交流与学习&#xff0c;若学者用学到的东西做一些与网络安全不相关的事情&#xff0c;结果均与本人无关&#xff01;&#xff01;&#xff01; 靶场环境: 使用kali作为hacker的攻击机器&#xff0c;来对web pc dc进行攻击。 这里声明一下: 关于…

Cesium billboard 自定义shader实现描边效果

Cesium billboard 自定义shader实现描边效果 uniform sampler2D u_atlas;uniform vec2 dimensions;in vec2 v_textureCoordinates;in vec4 v_pickColor;in vec4 v_color;in float v_splitDirection;void main(){if (v_splitDirection < 0.0 && gl_FragCoord.x > …

一文详解可视化大屏技术在地震监测中的作用!

昨天&#xff0c;安徽合肥市肥东县发生地震&#xff0c;震级达到4.7级&#xff0c;震源深度12千米。这一事件再次提醒我们&#xff0c;地震的威胁无处不在&#xff0c;及时有效的地震预警对于减少灾害损失至关重要。四川省作为地震活动频繁的地区&#xff0c;近年来在地震监测和…

配置环境-keil

配置keil -- 先将keil安装配置好&#xff0c;包括库 一、STM32 -- STM32是意法半导体&#xff08;意大利&#xff09;采用ARM公司设计的内核&#xff0c;设计一系列32位单片机芯片。 1、STM32开发的几种方式 2、STM32寄存器和库函数版本的工程创建 新建文件夹 复制相关文件…

【机器学习(八)】分类和回归任务-因子分解机(Factorization Machines,FM)-Sentosa_DSML社区版

文章目录 一、算法概念二、算法原理&#xff08;一&#xff09; FM表达式&#xff08;二&#xff09;时间复杂度&#xff08;三&#xff09;回归和分类 三、算法优缺点&#xff08;一&#xff09;优点&#xff08;二&#xff09;缺点 四、FM分类任务实现对比&#xff08;一&…

【2024华为杯研究生数学建模竞赛】比赛思路、代码、论文更新中.....

目录 赛中助攻华为杯常用建模算法&#x1f5d2;️&#x1f5d2;️历年优秀论文⭐⭐论文模板1&#xff09;论文模板2&#xff09;基础画图能力 绘图与数据分析软件SPSSPRO 2024研究生数学建模竞赛时间为9月21日&#xff08;周六&#xff09;8:00至9月25日&#xff08;周三&#…

互联网前端之 CSS 常见属性与三层结构

目录 现在互联网前端三层 CSS 常见属性 关注作者微信公众号&#xff0c;开启探索更多 CSS 知识的精彩之旅。在这里&#xff0c;你将收获丰富的CSS专业内容&#xff0c;深入了解这一网页开发语言的奥秘&#xff0c;不断拓展你的知识边界&#xff0c;提升技能水平。快来关注吧&…

对想学习人工智能或者大模型技术从业者的建议,零基础入门到精通,收藏这一篇就够了

“ 技术的价值在于应用&#xff0c;理论与实践相结合才能事半功倍**”** 写这个关于AI技术的公众号也有差不多五个月的时间了&#xff0c;最近一段时间基本上都在保持日更状态&#xff0c;而且写的大部分都是关于大模型技术理论和技术方面的东西。‍‍‍‍‍‍‍‍‍ 然后最近…

Windows安全日志分析(事件ID详解)

目录 如何查看Windows安全日志 常见事件ID列表 事件ID 1116 - 防病毒软件检测到恶意软件 事件ID 4624 - 账户登录成功 事件ID 4625 - 账户登录失败 事件ID 4672 - 为新登录分配特殊权限 事件ID 4688 - 新进程创建 事件ID 4689 - 进程终止 事件ID 4720 - 用户账户创建 …

3款免费的GPT类工具

前言 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;的崛起与发展已经成为我们生活中不可或缺的一部分。它的出现彻底改变了我们与世界互动的方式&#xff0c;并为各行各业带来了前所未有的便利。 一、Kimi 网址&#xff1a;点我前往 国产AI模型Kimi是一…

C++第八节课 日期类的补充

在上节课我们提交的代码中&#xff0c;还有着一些不足&#xff1a; 如果我们想要运行下面的函数&#xff1a; void test4() {Date d1(2023, 5, 5);d1 -50;d1.Print();Date d2(2023, 5, 5);d2 - -50;d2.Print(); } 我们发现之前的代码没有考虑day为负数的情况&#xff0c;可以…

浅谈红外测温技术在变电站运维中的应用

0引言 随着市场经济的繁荣发展&#xff0c;社会对电力的需求持续增长。城市供电网络的规模和用电设备的总量也在不断扩大&#xff0c;这导致城市电力系统中潜在的网络安全隐患日益增多。作为电力系统核心组成部分的变压器&#xff0c;其安全、稳定的工作直接关系到电能的质量和…

俄罗斯的Alexey V. Gubin开发的数据恢复文件-零假设恢复只读模式下对扫描/恢复数据起作用-供大家学习研究参考

// 主要特征 // Windows FAT,NTFS,Linux ext2 / 3/4和XFS卷格式化的驱动器或“ RAW文件系统”外部驱动器,USB拇指驱动器和存储卡带有ZAR Data Recovery免费版本的数码照片恢复RAID数据恢复NAS数据恢复MBR损坏数据恢复具有多个逻辑驱动器的分区表恢复支持长文件名和国家文件名…