配置文件读写这里就不详细介绍了,主要的配置文件格式如下
[reactor]ip = 127.0.0.1port = 7777maxConn = 1024threadNum = 5
一个主题,下面很多key-value的键值对.
代码如下。
11.1 功能实现
lars_reactor/include/config_file.h
#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
#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
[reactor]ip = 127.0.0.1port = 7777maxConn = 1024threadNum = 5
server.cpp
#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;}
