目录
1.回顾测试
2.mprpc框架的配置文件加载
2.1 mprpcconfig.h
2.2 完善mprpcapplication.h
2.3 完善mprpcapplication.cc
2.4 mprpcconfig.cc
2.5 test.conf
2.6 测试运行
3.扩展问题
1.回顾测试
我们先把之前的项目代码工程编译好,然后进入bin里面,执行
./provider
显示我们之前编的代码正确了!
接下来,我们开始编写配置文件
2.mprpc框架的配置文件加载
一开始编写的代码,读取配置文件信息时没有处理好,导致打印结果有多余的空行。
调试信息如下:
由上图可见是多读了一个\n导致的,更改后如下:
2.1 mprpcconfig.h
在src的include中创建头文件:mprpcconfig.h
#pragma once
#include <unordered_map>
#include <string>
//rpcserverip rpcserverport zookeeperip zookeeperport
//框架读取配置文件类
class MprpcConfig
{
public:
//负责解析加载配置文件
void LoadConfigFile(const char* config_file);
//查询配置项信息
std::string Load(const std::string& key);//返回key所对应的值-字符串
private:
std::unordered_map<std::string,std::string> m_configMap;
//去掉字符串前后的空格
void Trim(std::string& src_buf);
};
2.2 完善mprpcapplication.h
#pragma once
#include "mprpcconfig.h"
//mprpc框架的基础类,负责框架的一些初始化操作
class MprpcApplication
{
public:
static void Init(int argc,char** argv);//初始化
//单例模式
static MprpcApplication& GetInstance();//定义获取唯一实例的方法
private:
static MprpcConfig m_config;
MprpcApplication(){}//构造函数
MprpcApplication(const MprpcApplication&)=delete;//将与拷贝构造有关的函数delete
MprpcApplication(MprpcApplication&&) = delete;
};
2.3 完善mprpcapplication.cc
#include "mprpcapplication.h"
#include <iostream>
#include <unistd.h>
MprpcConfig MprpcApplication::m_config;
void ShowArgsHelp()
{
std::cout<<"format: command -i <configfile>"<<std::endl;
}
void MprpcApplication::Init(int argc, char **argv) // 初始化
{
if(argc<2)
{
ShowArgsHelp();
exit(EXIT_FAILURE);
}
int c=0;
std::string config_file;
while((c=getopt(argc,argv,"i:"))!=-1)
{
switch(c)
{
case 'i':
config_file=optarg;
break;
case '?':
//std::cout<<"invalid args!"<<std::endl;
ShowArgsHelp();
exit(EXIT_FAILURE);
case ':':
//std::cout<<"need <configfile>"<<std::endl;
ShowArgsHelp();
exit(EXIT_FAILURE);
default:
break;
}
}
//开始加载配置文件了 rpcserver_ip= rpcserver_port zookeeper_ip= zookeeper_port=
m_config.LoadConfigFile(config_file.c_str());
// std::cout<<"rpcserverip:"<<m_config.Load("rpcserverip")<<std::endl;
// std::cout<<"rpcserverport:"<<m_config.Load("rpcserverport")<<std::endl;
// std::cout<<"zookeeperip:"<<m_config.Load("zookeeperip")<<std::endl;
// std::cout<<"zookeeperport:"<<m_config.Load("zookeeperport")<<std::endl;
}
// 单例模式
MprpcApplication &MprpcApplication::GetInstance() // 定义获取唯一实例的方法
{
static MprpcApplication app;
return app;
}
2.4 mprpcconfig.cc
在src下创建文件mprpcconfig.cc
#include "mprpcconfig.h"
#include <iostream>
//负责解析加载配置文件
void MprpcConfig::LoadConfigFile(const char* config_file)
{
FILE* pf=fopen(config_file,"r");
if(nullptr==pf)
{
std::cout<<config_file<<" is note exist!"<<std::endl;
exit(EXIT_FAILURE);
}
//1.注释 2.正确的配置项 = 3.去掉开头的多余空格
while(!feof(pf))
{
char buf[512]={0};
fgets(buf,512,pf);
//去掉字符串前面多余的空格
std::string read_buf(buf);
Trim(read_buf);
//判断#的注释
if(read_buf[0]=='#'||read_buf.empty())
{
continue;
}
//解析配置项
int idx=read_buf.find('=');
if(idx==-1)
{
//配置项不合法
continue;
}
std::string key;
std::string value;
key=read_buf.substr(0,idx);
Trim(key);
//rpcserverip=127.0.0.1\n
int endidx=read_buf.find('\n',idx);//从等号之后开始寻找\n
value=read_buf.substr(idx+1,endidx-idx-1);
Trim(value);
m_configMap.insert({key,value});
}
}
// 查询配置项信息
std::string MprpcConfig::Load(const std::string &key)
{
//return m_configMap[key];//不要使用[],会产生副作用,正常情况key如果不存在,会返回空,可是用[]的话,会在map表中增加一对值
auto it=m_configMap.find(key);
if(it==m_configMap.end())
{
return "";
}
return it->second;
}
void MprpcConfig::Trim(std::string &src_buf)
{
int idx = src_buf.find_first_not_of(' ');
if (idx != -1)
{
// 说明字符串前面有空格
src_buf = src_buf.substr(idx, src_buf.size() - idx); // 第一个参数是下标,第二个是长度
}
// 去掉字符串后面多余的空格
idx = src_buf.find_last_not_of(' ');
if (idx != -1)
{
// 说明字符串后面有空格
src_buf = src_buf.substr(0, idx + 1);
}
}
2.5 test.conf
在bin下创建一个配置文件:test.conf
#rpc节点的ip地址
rpcserverip=127.0.0.1
#rpc节点的port端口号
rpcserverport=8000
#zk的ip地址
zookeeperip=127.0.0.1
#zk的port端口号
zookeeperport=5000
2.6 测试运行
编译:
测试结果:
3.扩展问题
C++中的容器都不是线程安全的,需要解决这个问题吗?
不需要考虑线程安全,因为整个提供rpc服务的站点启动以后,框架只需要init一次,不需要多线程。为了防止框架被多次初始化,可以在mprpcapplication.h文件中添加一个静态变量,来记录框架是否被初始化。