欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > routine.hpp路由匹配模块

routine.hpp路由匹配模块

2025/9/16 7:28:18 来源:https://blog.csdn.net/lzfnb666/article/details/141233510  浏览:    关键词:routine.hpp路由匹配模块

一.路由匹配模块介绍

路由匹配模块可以验证路由键(routing key)和绑定键(binding key)的合法性,并根据不同的交换机类型(如DirectFanoutTopic)进行消息的路由匹配。

二.Routine类的实现

设计思路

在消息队列系统中,消息路由是一个关键的功能。
交换机根据路由键将消息发送到与其匹配的队列,而不同类型的交换机有不同的路由规则。Routine类的设计目标是处理这些规则:

  1. 合法性校验:验证路由键和绑定键的字符规则是否符合预期。例如,routing_key只允许字母、数字、点和下划线,而binding_key还允许通配符(*#)。
  2. 路由匹配算法:根据交换机类型,确定routing_key和binding_key是否匹配,特别是在Topic类型的交换机中,复杂的匹配规则需要使用动态规划来实现

代码细节分析

合法性校验

routineKeyValid()方法用于验证路由键是否合法,允许的字符包括字母、数字、点和下划线。
bindingKeyValid()方法则允许更多字符,包括通配符*#,并对绑定键的格式进行了更严格的检查。例如,*#必须独立作为单词出现,且#不能和其他通配符同时出现。

 static bool routineKeyValid(const std::string &rkey){// 包含的字符规则: 0-9,a-z,A-Z, . _for (auto &ch : rkey){if (ch >= '0' && ch <= '9' ||ch >= 'a' && ch <= 'z' ||ch >= 'A' && ch <= 'Z' ||ch == '.' || ch == '_')continue;elsereturn false;}return true;}static bool bindingKeyValid(const std::string &bkey){// 1. 包含的字符规则 0-9,a-z,A-Z, . _ * #for (auto &ch : bkey){if (ch >= '0' && ch <= '9' ||ch >= 'a' && ch <= 'z' ||ch >= 'A' && ch <= 'Z' ||ch == '.' || ch == '_' ||ch == '*' || ch == '#')continue;elsereturn false;}// 2. 单词直接以.作为分隔符,#和* 必须独立作为单词出现std::vector<std::string> words;StrHelper::split(bkey, ".", words);for (auto &word : words){if (word.size() > 1 &&(word.find('*') != std::string::npos ||word.find('#') != std::string::npos))return false;}// 3. #可以匹配0-n个单词,即#前后不能有*和#的通配符for (int i = 1; i < words.size(); ++i){if (words[i] == "#" && words[i - 1] == "#")return false;else if (words[i] == "#" && words[i - 1] == "*")return false;else if (words[i] == "*" && words[i - 1] == "#")return false;}return true;}
路由匹配

route()方法根据不同的交换机类型决定是否匹配成功:

DIRECT类型:路由键和绑定键必须完全相等。

FANOUT类型:无论路由键如何,都会匹配成功。

TOPIC类型:使用动态规划(DP)方法实现复杂的通配符匹配逻辑。
首先将路由键和绑定键按.分隔为多个单词,然后通过DP表逐步匹配各个单词。
如果绑定键包含#*,则会根据通配符的规则处理。

动态规划的应用

DP表的初始化确保了在开始时没有匹配任何字符时(dp[0][0])的正确性。如果绑定键的第一个字符是#,那么也允许匹配空路由键(dp[1][0])。

在填充DP表时,#可以匹配零个或多个单词,而*则只能匹配一个单词。这种设计有效地解决了通配符的匹配问题。

实现总结

Routine类处理了不同类型的消息路由需求,特别是在处理Topic类型的复杂路由规则时,使用了动态规划来高效地完成匹配。

三.全部代码

#pragma once
#include "../common_mq/helper.hpp"
#include "../common_mq/logger.hpp"
#include "../common_mq/msg.pb.h"namespace mq
{class Routine{public:static bool routineKeyValid(const std::string &rkey){// 包含的字符规则: 0-9,a-z,A-Z, . _for (auto &ch : rkey){if (ch >= '0' && ch <= '9' ||ch >= 'a' && ch <= 'z' ||ch >= 'A' && ch <= 'Z' ||ch == '.' || ch == '_')continue;elsereturn false;}return true;}static bool bindingKeyValid(const std::string &bkey){// 1. 包含的字符规则 0-9,a-z,A-Z, . _ * #for (auto &ch : bkey){if (ch >= '0' && ch <= '9' ||ch >= 'a' && ch <= 'z' ||ch >= 'A' && ch <= 'Z' ||ch == '.' || ch == '_' ||ch == '*' || ch == '#')continue;elsereturn false;}// 2. 单词直接以.作为分隔符,#和* 必须独立作为单词出现std::vector<std::string> words;StrHelper::split(bkey, ".", words);for (auto &word : words){if (word.size() > 1 &&(word.find('*') != std::string::npos ||word.find('#') != std::string::npos))return false;}// 3. #可以匹配0-n个单词,即#前后不能有*和#的通配符for (int i = 1; i < words.size(); ++i){if (words[i] == "#" && words[i - 1] == "#")return false;else if (words[i] == "#" && words[i - 1] == "*")return false;else if (words[i] == "*" && words[i - 1] == "#")return false;}return true;}// 路由匹配是否成功static bool route(msg::ExchangeType type, const std::string &rkey, const std::string &bkey){if (type == msg::ExchangeType::DIRECT)return rkey == bkey;else if (type == msg::ExchangeType::FANOUT)return true;else//TOPIC{// 1.字符串分别以.为分隔符切分std::vector<std::string> rkeys;size_t routine_sz = StrHelper::split(rkey, ".", rkeys);std::vector<std::string> bkeys;size_t bind_sz = StrHelper::split(bkey, ".", bkeys);// 2.创建dp表std::vector<std::vector<bool>> dp(bind_sz+1,std::vector<bool>(routine_sz+1,false));// 3.初始化dp表// dp[0][0]=true// binding_key起始字符为0时,dp[1][0]=truedp[0][0]=true;if(bind_sz>0 && bkeys[0] == "#")dp[1][0] = true;// 4.填充dp表for(int i=1;i<=bind_sz;i++){for(int j=1;j<=routine_sz;j++){if(bkeys[i-1] == "#")dp[i][j] = dp[i-1][j-1] | dp[i][j-1] | dp[i-1][j];else if(bkeys[i-1] == "*" || bkeys[i-1] == rkeys[j-1])dp[i][j] = dp[i-1][j-1];}}// 5.返回最后一个元素return dp[bind_sz][routine_sz];}}};
};

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com