文章目录
- [1 Zinx框架总览](#1 Zinx框架总览)
- [2 三层模式的分析](#2 三层模式的分析)
- [3 三层重构原有的功能 - 头文件](#3 三层重构原有的功能 - 头文件)
-
- [3.1 通道层Stdin和Stdout类](#3.1 通道层Stdin和Stdout类)
-
- [3.1.2 StdInChannel](#3.1.2 StdInChannel)
- [3.1.2 StdOutChannel](#3.1.2 StdOutChannel)
- [3.2 协议层CmdCheck和CmdMsg类](#3.2 协议层CmdCheck和CmdMsg类)
-
- [3.2.1 CmdCheck单例模式](#3.2.1 CmdCheck单例模式)
-
- [3.2.1.1 单例模式](#3.2.1.1 单例模式)
- [3.2.1.2 * 命令识别类向业务层不同类别做分发](#3.2.1.2 * 命令识别类向业务层不同类别做分发)
- [3.2.2 CmdMsg自定义用户信息类,继承UserData](#3.2.2 CmdMsg自定义用户信息类,继承UserData)
- [3.3 业务层:回显类, 输出通道控制类, 日期前缀管理类](#3.3 业务层:回显类, 输出通道控制类, 日期前缀管理类)
-
- [3.3.1 回显对象EchoRole](#3.3.1 回显对象EchoRole)
- [3.3.2 控制输入输出](#3.3.2 控制输入输出)
- [3.3.3 日期管理类](#3.3.3 日期管理类)
1 Zinx框架总览
2 三层模式的分析
3 三层重构原有的功能 - 头文件
三层结构重构原有功能
- 自定义消息类,继承UserData,添加一个成员变量szUserData
- 定义多个Role类继承Irole,重写ProcMsg函数,进行不同处理
- 定义protocol类,继承Iprotocol,重写四个函数,两个函数时原始
数据和用户数据之间的转换;另两个用来找消息处理对象和消息发
送对象。 - 定义channel类,继承Ichannel,在getnextinputstage函数中返回协
议对象
3.1 通道层Stdin和Stdout类
通道类,派生自基础处理者类,提供基于系统调用的数据收发功能
一般地,用户应该根据处理的文件(信息源)不同而创建通道类的子类或选用合适的实用类(已经提供的通道类子类)来完成系统级文件IO
c
class StdInChannel :
public Ichannel
{
public:
StdInChannel();
virtual ~StdInChannel();
// 通过 Ichannel 继承
virtual bool Init() override;
virtual bool ReadFd(std::string& _input) override;
virtual bool WriteFd(std::string& _output) override;
virtual void Fini() override;
virtual int GetFd() override;
virtual std::string GetChannelInfo() override;
virtual AZinxHandler* GetInputNextStage(BytesMsg& _oInput) override;
};
class StdOutChannel :public Ichannel
{
// 通过 Ichannel 继承
virtual bool Init() override;
virtual bool ReadFd(std::string& _input) override;
virtual bool WriteFd(std::string& _output) override;
virtual void Fini() override;
virtual int GetFd() override;
virtual std::string GetChannelInfo() override;
virtual AZinxHandler* GetInputNextStage(BytesMsg& _oInput) override;
};
3.1.2 StdInChannel
cpp
bool StdInChannel::ReadFd(std::string& _input)
{
cin >> _input;
return true;
}
bool StdInChannel::WriteFd(std::string& _output)
{
return false;
}
int StdInChannel::GetFd()
{
return 0;
}
std::string StdInChannel::GetChannelInfo()
{
return "stdin";
}
AZinxHandler* StdInChannel::GetInputNextStage(BytesMsg& _oInput)
{
/*返回协议对象*/
return CmdCheck::GetInstance();
}
3.1.2 StdOutChannel
c
bool StdOutChannel::ReadFd(std::string& _input)
{
return false;
}
bool StdOutChannel::WriteFd(std::string& _output)
{
cout << _output << endl;
return true;
}
int StdOutChannel::GetFd()
{
return 1;
}
std::string StdOutChannel::GetChannelInfo()
{
return "stdout";
}
AZinxHandler* StdOutChannel::GetInputNextStage(BytesMsg& _oInput)
{
return nullptr;
}
3.2 协议层CmdCheck和CmdMsg类
3.2.1 CmdCheck单例模式
- 原始数据和业务数据相互函数,开发者重写该函数,实现协议
- 获取处理角色对象函数,开发者应该重写该函数,用来指定当前产生的用户数据消
- 获取发送通道函数,开发者应该重写该函数,用来指定当前字节流应该由哪个通道对象发出
csharp
class CmdCheck :
public Iprotocol
{
CmdCheck();
virtual ~CmdCheck();
static CmdCheck *poSingle;
public:
// 通过 Iprotocol 继承
/*原始数据和业务数据相互函数,开发者重写该函数,实现协议*/
virtual UserData * raw2request(std::string _szInput) override;
virtual std::string * response2raw(UserData & _oUserData) override;
/*获取处理角色对象函数,开发者应该重写该函数,用来指定当前产生的用户数据消息应该传递给哪个角色处理*/
virtual Irole * GetMsgProcessor(UserDataMsg & _oUserDataMsg) override;
/*获取发送通道函数,开发者应该重写该函数,用来指定当前字节流应该由哪个通道对象发出*/
virtual Ichannel * GetMsgSender(BytesMsg & _oBytes) override;
static CmdCheck *GetInstance() {
return poSingle;
}
std::string szOutChannel;
};
3.2.1.1 单例模式
构造全局唯一的协议对象
c
#include "CmdCheck.h"
#include "CmdMsg.h"
#include "EchoRole.h"
using namespace std;
CmdCheck *CmdCheck::poSingle = new CmdCheck();
3.2.1.2 * 命令识别类向业务层不同类别做分发
通过是不是命令来进行区分:if (isCmd)
c
Irole * CmdCheck::GetMsgProcessor(UserDataMsg & _oUserDataMsg)
{
szOutChannel = _oUserDataMsg.szInfo;
if ("stdin" == szOutChannel)
{
szOutChannel = "stdout";
}
/*根据命令不同,交给不同的处理role对象*/
auto rolelist = ZinxKernel::Zinx_GetAllRole();
auto pCmdMsg = dynamic_cast<CmdMsg *>(_oUserDataMsg.poUserData);
/*读取当前消息是否是命令*/
bool isCmd = pCmdMsg->isCmd;
Irole *pRetRole = NULL;
for (Irole *prole : rolelist)
{
if (isCmd)
{
auto pOutCtrl = dynamic_cast<OutputCtrl *>(prole);
if (NULL != pOutCtrl)
{
pRetRole = pOutCtrl;
break;
}
}
else
{
auto pDate = dynamic_cast<DatePreRole *>(prole);
if (NULL != pDate)
{
pRetRole = pDate;
break;
}
}
}
return pRetRole;
}
3.2.2 CmdMsg自定义用户信息类,继承UserData
cpp
class CmdMsg :
public UserData
{
public:
/*成员变量表示要回显的字符串*/
std::string szUserData;
/*开启输出标志*/
bool isOpen = true;
/*该消息是命令*/
bool isCmd = false;
/*要加前缀*/
bool needDatePre = false;
CmdMsg();
virtual ~CmdMsg();
};
3.3 业务层:回显类, 输出通道控制类, 日期前缀管理类
3.3.1 回显对象EchoRole
主要有init, procmsg,fini三个函数
cpp
#pragma once
#include <zinx.h>
class EchoRole :
public Irole
{
public:
EchoRole();
virtual ~EchoRole();
// 通过 Irole 继承
virtual bool Init() override;
virtual UserData * ProcMsg(UserData & _poUserData) override;
virtual void Fini() override;
};
- 容易出错的点:参数一必须是一个堆对象
cpp
UserData * EchoRole::ProcMsg(UserData & _poUserData)
{
/*写出去*/
GET_REF2DATA(CmdMsg, input, _poUserData);
CmdMsg *pout = new CmdMsg(input);
ZinxKernel::Zinx_SendOut(*pout, *(CmdCheck::GetInstance()));
return nullptr;
}
3.3.2 控制输入输出
- 写一个关闭输出的角色类,摘除输出通道或添加输出通道
- 在CmdMsg用户数据类中添加开关标志,是否是命令标志
- 在协议类中,根据输入字符串,设置开关标志和是否是命令的标志
- 在协议类分发消息时,判断是否是命令,是命令则发给关闭输出角 色类,否则发给回显角色类
c
class OutputCtrl :public Irole {
// 通过 Irole 继承
virtual bool Init() override;
virtual UserData * ProcMsg(UserData & _poUserData) override;
virtual void Fini() override;
Ichannel *pOut = NULL;
};
3.3.3 日期管理类
cpp
class DatePreRole :public Irole {
// 通过 Irole 继承
virtual bool Init() override;
virtual UserData * ProcMsg(UserData & _poUserData) override;
virtual void Fini() override;
bool needAdd = false;
};