多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 11) 配置文件读写功能 ​ 配置文件读写这里就不详细介绍了,主要的配置文件格式如下 ```conf [reactor] ip = 127.0.0.1 port = 7777 maxConn = 1024 threadNum = 5 ``` ​ 一个主题,下面很多key-value的键值对. 代码如下。 ### 11.1 功能实现 > lars_reactor/include/config_file.h ```c #pragma once #include <string> #include <vector> #include <map> //定义一个存放配置信息的map //key 是string 存放一个标题section //value 是一个map 存放该标题下面的所有key-value键值对 typedef std::map<std::string, std::map<std::string, std::string> *> STR_MAP; typedef STR_MAP::iterator STR_MAP_ITER; //设计成单例模式 class config_file { public: ~config_file(); //获取字符串类型配置信息 std::string GetString(const std::string& section, const std::string& key, const std::string& default_value = ""); //字符串集合配置信息 std::vector<std::string> GetStringList(const std::string& section, const std::string& key); //获取整型类型配置信息 unsigned GetNumber(const std::string& section, const std::string& key, unsigned default_value = 0); //获取布尔类型配置信息 bool GetBool(const std::string& section, const std::string& key, bool default_value = false); //获取浮点类型配置信息 float GetFloat(const std::string& section, const std::string& key, const float& default_value); //设置配置文件所在路径 static bool setPath(const std::string& path); //获取单例 static config_file *instance(); private: config_file() { } //构造私有 //字符串配置文件解析基础方法 bool isSection(std::string line, std::string& section); unsigned parseNumber(const std::string& s); std::string trimLeft(const std::string& s); std::string trimRight(const std::string& s); std::string trim(const std::string& s); bool Load(const std::string& path); static config_file *config;//唯一读取配置文件实例 STR_MAP _map; }; ``` > lars_reactor/src/config_file.cpp ```c #include "config_file.h" #include <map> #include <fstream> #include <iostream> #include <sstream> #include <assert.h> #include <strings.h> config_file* config_file::config = NULL; config_file::~config_file() { for (STR_MAP_ITER it = _map.begin(); it != _map.end(); ++it) { delete it->second; } } //获取字符串类型键值对 std::string config_file::GetString(const std::string& section, const std::string& key, const std::string& default_value) { STR_MAP_ITER it = _map.find(section); if (it != _map.end()) { std::map<std::string, std::string>::const_iterator it1 = it->second->find(key); if (it1 != it->second->end()) { return it1->second; } } return default_value; } //获取浮点类型键值对 float config_file::GetFloat(const std::string& section, const std::string& key, const float& default_value) { std::ostringstream convert1; convert1 << default_value; //将浮点转换成字符串,然后按照字符串业务处理 std::string default_value_str = convert1.str(); std::string text = GetString(section, key, default_value_str); std::istringstream convert2(text); float fresult; if (!(convert2 >> fresult)) //如果Result放不下text对应的数字,执行将返回0; fresult = 0; return fresult; } //价值配置文件 bool config_file::Load(const std::string& path) { std::ifstream ifs(path.c_str()); if (!ifs.good()) { return false; } std::string line; std::map<std::string, std::string> *m = NULL; while (!ifs.eof() && ifs.good()) { getline(ifs, line); std::string section; if (isSection(line, section)) { STR_MAP_ITER it = _map.find(section); if (it == _map.end()) { m = new std::map<std::string, std::string>(); _map.insert(STR_MAP::value_type(section, m)); } else { m = it->second; } continue; } size_t equ_pos = line.find('='); if (equ_pos == std::string::npos) { continue; } std::string key = line.substr(0, equ_pos); std::string value = line.substr(equ_pos + 1); key = trim(key); value = trim(value); if (key.empty()) { continue; } if (key[0] == '#' || key[0] == ';') // skip comment { continue; } std::map<std::string, std::string>::iterator it1 = m->find(key); if (it1 != m->end()) { it1->second = value; } else { m->insert(std::map<std::string, std::string>::value_type(key, value)); } } ifs.close(); return true; } std::vector<std::string> config_file::GetStringList(const std::string& section, const std::string& key) { std::vector<std::string> v; std::string str = GetString(section, key, ""); std::string sep = ", \t"; std::string substr; std::string::size_type start = 0; std::string::size_type index; while ((index = str.find_first_of(sep, start)) != std::string::npos) { substr = str.substr(start, index - start); v.push_back(substr); start = str.find_first_not_of(sep, index); if (start == std::string::npos) { return v; } } substr = str.substr(start); v.push_back(substr); return v; } //获取整型类型键值对 unsigned config_file::GetNumber(const std::string& section, const std::string& key, unsigned default_value) { STR_MAP_ITER it = _map.find(section); if (it != _map.end()) { std::map<std::string, std::string>::const_iterator it1 = it->second->find(key); if (it1 != it->second->end()) { return parseNumber(it1->second); } } return default_value; } //获取布尔类型键值对 bool config_file::GetBool(const std::string& section, const std::string& key, bool default_value) { STR_MAP_ITER it = _map.find(section); if (it != _map.end()) { std::map<std::string, std::string>::const_iterator it1 = it->second->find(key); if (it1 != it->second->end()) { if (strcasecmp(it1->second.c_str(), "true") == 0) { return true; } } } return default_value; } bool config_file::isSection(std::string line, std::string& section) { section = trim(line); if (section.empty() || section.length() <= 2) { return false; } if (section.at(0) != '[' || section.at(section.length() - 1) != ']') { return false; } section = section.substr(1, section.length() - 2); section = trim(section); return true; } unsigned config_file::parseNumber(const std::string& s) { std::istringstream iss(s); long long v = 0; iss >> v; return v; } std::string config_file::trimLeft(const std::string& s) { size_t first_not_empty = 0; std::string::const_iterator beg = s.begin(); while (beg != s.end()) { if (!isspace(*beg)) { break; } first_not_empty++; beg++; } return s.substr(first_not_empty); } std::string config_file::trimRight(const std::string& s) { size_t last_not_empty = s.length(); std::string::const_iterator end = s.end(); while (end != s.begin()) { end--; if (!isspace(*end)) { break; } last_not_empty--; } return s.substr(0, last_not_empty); } std::string config_file::trim(const std::string& s) { return trimLeft(trimRight(s)); } config_file *config_file::instance() { assert(config != NULL); return config; } //设置配置文件所在路径 bool config_file::setPath(const std::string& path) { assert(config == NULL); //创建对象 config = new config_file(); //加载文件 return config->Load(path); } ``` ### 11.2 完成Lars Reactor V0.9开发 > serv.conf ```conf [reactor] ip = 127.0.0.1 port = 7777 maxConn = 1024 threadNum = 5 ``` > server.cpp ```c #include "tcp_server.h" #include <string> #include <string.h> #include "config_file.h" //回显业务的回调函数 void callback_busi(const char *data, uint32_t len, int msgid, net_connection *conn, void *user_data) { printf("callback_busi ...\n"); //直接回显 conn->send_message(data, len, msgid); } //打印信息回调函数 void print_busi(const char *data, uint32_t len, int msgid, net_connection *conn, void *user_data) { printf("recv client: [%s]\n", data); printf("msgid: [%d]\n", msgid); printf("len: [%d]\n", len); } //新客户端创建的回调 void on_client_build(net_connection *conn, void *args) { int msgid = 101; const char *msg = "welcome! you online.."; conn->send_message(msg, strlen(msg), msgid); } //客户端销毁的回调 void on_client_lost(net_connection *conn, void *args) { printf("connection is lost !\n"); } int main() { event_loop loop; //加载配置文件 config_file::setPath("./serv.conf"); std::string ip = config_file::instance()->GetString("reactor", "ip", "0.0.0.0"); short port = config_file::instance()->GetNumber("reactor", "port", 8888); printf("ip = %s, port = %d\n", ip.c_str(), port); tcp_server server(&loop, ip.c_str(), port); //注册消息业务路由 server.add_msg_router(1, callback_busi); server.add_msg_router(2, print_busi); //注册链接hook回调 server.set_conn_start(on_client_build); server.set_conn_close(on_client_lost); loop.event_process(); return 0; } ``` --- ### 关于作者: 作者:`Aceld(刘丹冰)` mail: [danbing.at@gmail.com](mailto:danbing.at@gmail.com) github: [https://github.com/aceld](https://github.com/aceld) 原创书籍: [https://www.kancloud.cn/@aceld](https://www.kancloud.cn/@aceld) ![](https://img.kancloud.cn/b0/d1/b0d11a21ba62e96aef1c11d5bfff2cf8_227x227.jpg) >**原创声明:未经作者允许请勿转载, 如果转载请注明出处**