配置文件读写这里就不详细介绍了,主要的配置文件格式如下
[reactor]
ip = 127.0.0.1
port = 7777
maxConn = 1024
threadNum = 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.1
port = 7777
maxConn = 1024
threadNum = 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;
}