@TOC
目录
路由匹配模块
决定了一条消息是否能够发布到指定的队列
在每个队列根交换机的绑定信息中,都有一个binding_key(在虚拟机篇有说到)这是队列发布的匹配规则
在每条要发布的消息中,都有一个routing_key, 是消息的发布规则
交换机有三种交换类型:直接交换,广播交换,主题交换
广播交换:直接将消息发布给交换机的所有绑定队列
直接交换:routing_key和binding_key完全一致则匹配成功
主题交换:binding_key中是匹配规则 new.music.#, routing_key是消息规则 new.music.pop,匹配成功才能发布
-
提供一个判断routing_key与binding_key是否能够匹配成功的接口
-
判断 routing_key是否符合规定:
格式约定:只能由数字,字母,_ 构成
- 判断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