仿RabbitMq实现简易消息队列正式篇(路由匹配篇)

复制代码
@TOC

目录

路由匹配模块

代码展示


路由匹配模块

决定了一条消息是否能够发布到指定的队列

在每个队列根交换机的绑定信息中,都有一个binding_key(在虚拟机篇有说到)这是队列发布的匹配规则

在每条要发布的消息中,都有一个routing_key, 是消息的发布规则

交换机有三种交换类型:直接交换,广播交换,主题交换

广播交换:直接将消息发布给交换机的所有绑定队列

直接交换:routing_key和binding_key完全一致则匹配成功

主题交换:binding_key中是匹配规则 new.music.#, routing_key是消息规则 new.music.pop,匹配成功才能发布

  1. 提供一个判断routing_key与binding_key是否能够匹配成功的接口

  2. 判断 routing_key是否符合规定:

格式约定:只能由数字,字母,_ 构成

  1. 判断binding_key是否符合规定:

格式约定只能由数字,字母,_,# ,* 构成

代码展示

复制代码
#ifndef __M_ROUTE_H_
#define __M_ROUTE_H_

#include <iostream>
#include "../mqcommon/logger.hpp"
#include "../mqcommon/helper.hpp"
#include "../mqcommon/msg.pb.h"

namespace mymq
{
    class Router
    {
    public:
        static bool isLegalRoutingKey(const std::string& routing_key)
        {
            // routing_key: 不需要判断是否包含有非法字符即可,合法字符(a ~ z, A ~ Z, 0 ~ 9, ....)
            for(auto& ch : routing_key)
            {
                if((ch >= 'a' && ch <= 'z') ||
                   (ch >= 'A' && ch <= 'Z') ||
                   (ch >= '1' && ch <= '9') ||
                   (ch == '_' || ch == '.'))
                   continue;
                return false;
            }
            return true;
        }
        static bool isLegalBindingKey(const std::string& binding_key)
        {
            for(auto& ch : binding_key)
            {
                if((ch >= 'a' && ch <= 'z') ||
                   (ch >= 'A' && ch <= 'Z') ||
                   (ch >= '1' && ch <= '9') ||
                   (ch == '_' || ch == '.') ||
                   (ch == '#' || ch == '*'))
                   continue;
                return false;
            }
            // 2. * 和 # 必须独立存在
            std::vector<std::string> sub_word;
            StrHelper::split(binding_key, ".", sub_word);
            for(std::string& word : sub_word)
            {
                if((word.size() > 1) && (word.find("*") != std::string::npos && (word.find("#") != std::string::npos)))
                {
                    return false;
                }
            }

            // 3. * 和 # 不能连续出现
            for(int i = 1; i < sub_word.size(); i++)
            {
                if(sub_word[i] == "*" && sub_word[i - 1] == "#")
                {
                    return false;
                }
                if(sub_word[i] == "#" && sub_word[i - 1] == "#")
                {
                    return false;
                }
                if(sub_word[i] == "#" && sub_word[i - 1] == "*")
                {
                    return false;
                }
            }
            return true;
        }

        static bool route(ExchangeType type, const std::string& routing_key, const std::string& binding_key)
        {
            if(type == ExchangeType::DIRECT)
            {
                return (routing_key == binding_key);
            }
            else if(type == ExchangeType::FANOUT)
            {
                return true;
            }
            // 主题交换 : 要进行模式匹配 : 
            // 1. 将 binding_key 与 routing_key 进行字符串分割,得到各个单词数组
            std::vector<std::string> bkeys, rkeys;
            int n_rkeys = StrHelper::split(routing_key, ".", rkeys);
            int n_bkeys = StrHelper::split(binding_key, ".", bkeys);
            // 2. 定义标记数组, 并初始化[0][0]位置为true, 其他位置为false
            std::vector<std::vector<bool>> dp(n_bkeys + 1, std::vector<bool>(n_rkeys + 1));
            dp[0][0] = true;
            //3. 如果binding_key以#开始,则将#对应的第0行全部为1
            for(int i = 1; i < n_bkeys; i++)
            {
                if(bkeys[i - 1] == "#")
                {
                    dp[i][0] = true;
                    continue;
                }
                break;
            }
            // 4. 使用routing_key中的每个单词与binding_key中的每个单词进行匹配并标记数组
            for(int i = 1; i < n_bkeys + 1; i++)
            {
                for(int j = 1; j < n_rkeys + 1; j++)
                {
                    if(bkeys[i - 1] == rkeys[j - 1] || bkeys[i - 1] == "*")
                    {
                        dp[i][j] = dp[i - 1][j - 1];
                    }
                    else if(bkeys[i - 1] == "#")
                    {
                        dp[i][j] = dp[i - 1][j - 1] | dp[i][j - 1] | dp[i - 1][j];
                    }
                }
            }
            return dp[n_bkeys][n_rkeys];
        }
    };
}

#endif
相关推荐
David猪大卫3 小时前
【Linux修炼】环境变量、进程地址空间
linux·c语言·经验分享·笔记·学习·ubuntu·centos
叼烟扛炮4 小时前
Linux 学习笔记(五十六):IO 多路复用初探——select 的“三宗罪”
linux·服务器·数据库·笔记·学习·php
汉克老师4 小时前
CSP-J 2026 第二轮入门组真题解析(第一题 、旅游)
c++·csp-j·信息学竞赛·小学生学c++
Ruiery4 小时前
Linux 6.6内核内存管理深度解析(十五):CMA 连续内存分配器
linux·运维·服务器
xiaoye-duck5 小时前
《C++ 项目:手写大模型接入 SDK》Gemini接口设计(上):初始化、全量响应实现和测试
开发语言·网络·c++·语言模型
测试界的小码农5 小时前
【Linux 命令实战(01):认识 Linux 终端,从零掌握第一个命令】
linux·运维·服务器
布裘6 小时前
【银河麒麟】重启后时区丢失?排查发现 localtime 被业务程序替换成硬链接
linux·运维·网络
nice_lcj5207 小时前
Java Lambda 表达式入门:怎么写、怎么用、常用方法有哪些
java·开发语言·后端·面试
码农小河668 小时前
基于SSM+JSP+MySQL的在线医疗服务系统的设计与实现
java·开发语言·mysql
GeW8 小时前
高端化转型进入“补底层”阶段:Linux与数据库的再定位
linux