重写Sylar基于协程的服务器(2、配置模块的设计)

2024-02-02 06:52

本文主要是介绍重写Sylar基于协程的服务器(2、配置模块的设计),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

重写Sylar基于协程的服务器(2、配置模块的设计)

重写Sylar基于协程的服务器系列:

重写Sylar基于协程的服务器(0、搭建开发环境以及项目框架 || 下载编译简化版Sylar)

重写Sylar基于协程的服务器(1、日志模块的架构)

重写Sylar基于协程的服务器(2、配置模块的设计)

重写Sylar基于协程的服务器(3、协程模块的设计)

配置模块存在的必要性

一个服务器软件可能会运行在不同的机器上,机器的配置、网络环境、实际需求等都是千变万化,在服务器软件中,为了适应这些变化,可能就是调整几个变量的值。开发人员不可能每次外在因素的改变就重新编译软件再发布,这明显是不现实的。于是配置模块就在这时发挥它的关键作用,利用好配置模块就不需要再次编译,让配置模块自己加载参数,动态调节就行了。

配置模块的设计与实现

配置模块序列化和反序列化效果(支持std::各种容器

YAML 的基本语法如下:

  1. 大小写敏感。

  2. 利用缩进表示层级关系,缩进只能使用空格,空格的数量不重要。

  3. '#'表示注释。

  4. 数据类型:对象,键值对的集合,即K-V对。数组,一组按次序排列的值。纯量(scalars),单个的、不可再分的值,包括字符串、布尔值、整数、浮点数、Null、时间、日期。

测试配置文件定义了一个key为space,value也是一个map类型的节点,该map有两个kv对,它们的key分别是vec、num,value分别是数组类型和纯量类型。如下

test_config.yml:

space:vec: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]num: 7

测试代码:

void test_logConfig(){// 创建配置变量lunar::ConfigVar<std::vector<int>>::ptr vec = lunar::ConfigVarMgr::GetInstance()->lookUp("space.vec", std::vector<int>(), "vec test");lunar::ConfigVar<int>::ptr num = lunar::ConfigVarMgr::GetInstance()->lookUp("space.num", int(), "num test");// 解析配置文件lunar::ConfigVarMgr::GetInstance()->loadFromFile("test_config.yml");// 反序列化配置 && 输出到控制台LUNAR_LOG_INFO(g_logger) << vec->toString();LUNAR_LOG_INFO(g_logger) << num->toString();
}

解析结果:

[root@localhost build]# ../bin/test_config 
2024-01-31 21:02:02     2433    unknow  4294967295      [INFO]  [system]        /root/workspace/lunar/tests/test_config.cc:53       - 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2024-01-31 21:02:02     2433    unknow  4294967295      [INFO]  [system]        /root/workspace/lunar/tests/test_config.cc:54       7

配置模块类的设计

在Yaml提供的数据类型的基础上,我们的配置文件还需要支持对象类型,所以我们需要通过模板,以泛型编程的方式实现对复杂数据类型的解析,除此之外,我们还要,对各个配置变量进行集中管理,综上所述,类的设计如下:

  1. LexicalCast,对象转换类模板(仿函数),使用C++的模板二次封装Boost库的boost::lexical_cast模板函数,实现基础类型和字符串类型间相互转换。然后对LexicalCast类模板进行偏特化,让其支持C++标准库的容器的序列化与反序列化。所以,我们实现的LexicalCast类模板默认支持基础类型和C++容器,想要支持自定义类型的序列化和反序列化,用户需要自己实现全特化LexicalCast。

  2. ConfigVarBase,配置变量基类,抽象出配置参数共有属性和方法比如变量名、对变量的描述、互斥锁、toString()、fromString()等,方便ConfigVarManager类使用多态对配置变量进行统一的管理。

  3. ConfigVar,配置变量类模板,继承ConfigVarBase类,含有m_value成员变量,利用LexicalCast类模板,实现toString方法将配置变量序列化成Yaml String,实现fromString方法将Yaml String反序列化成配置变量。此外,还支持变更通知,在set方法中调用变更回调,通知引用配置变量的地方更新变量。

  4. ConfigVarManager,配置变量管理类,利用std::map容器管理所有ConfigVar变量,std::map以配置变量名作为key,以配置变量基类智能指针作为value,支持配置变量的查询,用户在查询一条配置变量时,会提供该变量的变量名、默认值、变量描述,如果配置变量不存在,ConfigVarManager还会自动通过new 运算符利用默认值创建一个类型相同的配置变量,然后将<变量名,自动创建的配置变量>插到std::map中并返回给用户,因此ConfigVarManage还有自学习的能力。此外,提供了loadFromYaml函数支持对Yaml文件的解析,通过递归的方式解析Yaml文件中的每个map node节点,因为Yaml文件的map类型就是<key, value>对,这里key,value在配置文件中的含义和成员变量std::map中元素的含义是一致的,所以,取解析到的每个map node节点的key,去查该key是否存在于std::map成员中,如果存在,就调用相应配置变量基类的fronString函数,将map node的value作为参数,反序列化成一个配置变量。

ConfigVarManager的伪代码如下:

伪代码

yaml配置文件解析的核心代码如下:

    // 递归枚举每一个类型为map的节点。static void __ListAllYamlNode(std::string prefix,const YAML::Node& node,std::vector<std::pair<std::string, YAML::Node>>& output){output.push_back(std::make_pair(prefix, node));if(node.IsMap()){for(auto it = node.begin(); it != node.end(); it++){__ListAllYamlNode((prefix.empty() ? prefix :prefix + ".") + it->first.Scalar(), it->second, output);}}}void ConfigVarManager::loadFromFile(const std::string& val){std::vector<std::pair<std::string, YAML::Node>> nodes;YAML::Node root = YAML::LoadFile(val);__ListAllYamlNode("", root, nodes);for(auto it = nodes.begin(); it != nodes.end(); it++){ConfigVarBase::ptr var = lookUpConfigVarBaseByName(it->first);if(var != nullptr){ // 有配置变量就解析该节点std::stringstream ss("");ss << it->second;var->fromString(ss.str());// for debug//LUNAR_LOG_DEBUG(LUNAR_LOG_NAME("system")) << var->toString();}}}

关于yaml-cpp的使用可以参考官方文档:https://github.com/jbeder/yaml-cpp/wiki/Tutorial。

感兴趣的同学,可以阅读一下本文实现的源码:https://github.com/LunarStore/lunar


本章完结

这篇关于重写Sylar基于协程的服务器(2、配置模块的设计)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/669816

相关文章

Go语言开发实现查询IP信息的MCP服务器

《Go语言开发实现查询IP信息的MCP服务器》随着MCP的快速普及和广泛应用,MCP服务器也层出不穷,本文将详细介绍如何在Go语言中使用go-mcp库来开发一个查询IP信息的MCP... 目录前言mcp-ip-geo 服务器目录结构说明查询 IP 信息功能实现工具实现工具管理查询单个 IP 信息工具的实现服

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

SpringBoot基于配置实现短信服务策略的动态切换

《SpringBoot基于配置实现短信服务策略的动态切换》这篇文章主要为大家详细介绍了SpringBoot在接入多个短信服务商(如阿里云、腾讯云、华为云)后,如何根据配置或环境切换使用不同的服务商,需... 目录目标功能示例配置(application.yml)配置类绑定短信发送策略接口示例:阿里云 & 腾

如何为Yarn配置国内源的详细教程

《如何为Yarn配置国内源的详细教程》在使用Yarn进行项目开发时,由于网络原因,直接使用官方源可能会导致下载速度慢或连接失败,配置国内源可以显著提高包的下载速度和稳定性,本文将详细介绍如何为Yarn... 目录一、查询当前使用的镜像源二、设置国内源1. 设置为淘宝镜像源2. 设置为其他国内源三、还原为官方

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

Python中的getopt模块用法小结

《Python中的getopt模块用法小结》getopt.getopt()函数是Python中用于解析命令行参数的标准库函数,该函数可以从命令行中提取选项和参数,并对它们进行处理,本文详细介绍了Pyt... 目录getopt模块介绍getopt.getopt函数的介绍getopt模块的常用用法getopt模

CentOS7更改默认SSH端口与配置指南

《CentOS7更改默认SSH端口与配置指南》SSH是Linux服务器远程管理的核心工具,其默认监听端口为22,由于端口22众所周知,这也使得服务器容易受到自动化扫描和暴力破解攻击,本文将系统性地介绍... 目录引言为什么要更改 SSH 默认端口?步骤详解:如何更改 Centos 7 的 SSH 默认端口1

Maven的使用和配置国内源的保姆级教程

《Maven的使用和配置国内源的保姆级教程》Maven是⼀个项目管理工具,基于POM(ProjectObjectModel,项目对象模型)的概念,Maven可以通过一小段描述信息来管理项目的构建,报告... 目录1. 什么是Maven?2.创建⼀个Maven项目3.Maven 核心功能4.使用Maven H

SpringBoot多数据源配置完整指南

《SpringBoot多数据源配置完整指南》在复杂的企业应用中,经常需要连接多个数据库,SpringBoot提供了灵活的多数据源配置方式,以下是详细的实现方案,需要的朋友可以参考下... 目录一、基础多数据源配置1. 添加依赖2. 配置多个数据源3. 配置数据源Bean二、JPA多数据源配置1. 配置主数据

Spring 基于XML配置 bean管理 Bean-IOC的方法

《Spring基于XML配置bean管理Bean-IOC的方法》:本文主要介绍Spring基于XML配置bean管理Bean-IOC的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一... 目录一. spring学习的核心内容二. 基于 XML 配置 bean1. 通过类型来获取 bean2. 通过