目录
协议无处不在,正是因为统一协议接口的存在,软件可以运行再各种软件上,各种语言都可以编写移动端桌面端软件。
- 个人总结的数据协议编程进阶技巧,总结如下七层 。
Level 1 无模式
std::cout << "Level 1 无模式\n";
Level 2 简单模式,数据分离
//Level 2
// 方法
auto DoPrint = [](const char* data)
{
std::cout << data;
std::cout << "\n";
};
// 数据
const char* data = GetData("Level 2 简单模式,数据分离\n");
// 业务执行
DoPrint(data);
Level 3 简单模式,数据与方法分离
using DoMethodVRetPStr = void(const char*);
const char* data2 = GetData("Level 3 简单模式,数据与方法分离\n");
DoMethodVRetPStr *method1 = DoPrint;
method1(data2);
Level 4 简单协议模式
// 简单接口协议定义
struct DataProtocol
{
const char* m_para;
DoMethodVRetPStr* m_handler;
};
// 数据容器,存储支持的业务类型
DataProtocol testData[] = {
{"Level 4 简单协议模式", DoPrint},
{"...", DoOthers},
{nullptr, nullptr}
};
// 接口解析器
auto TestProtocol = [](DataProtocol& data) ->void
{
data.m_handler(data.m_para);
};
// 业务层调用接口,其他
TestProtocol(testData[0]);
Level 5 文本协议
使用文本协议定义
- 类似于http 文本协议,制定类似以下文本协议请求(此处借用json数据格式,现今数据格式众多,比如xml, protobuf, bson,)
- 当然也可以纯二进制协议(可参考UDP/TCP协议如何定义的,访问国际通用的RFC网站,https://datatracker.ietf.org/doc/rfc793/)
- 还可以文本与二进制混合的文本协议(http就是文本与二进制混合的协议,图片音视频都可以传输)
例如 “{ “method”:“DoPrint”,“data”:“通用定制化文本协议模式” }”;
实现如下代码:
// 定义接口协议
enum class EKeyType:int
{
eKeyType_Data = 0,
eKeyType_Method,
eKeyType_Loop
};
std::map<EKeyType, const char *> KeyConfigs = {
{EKeyType::eKeyType_Data,"data"},
{EKeyType::eKeyType_Loop,"loop"},
{EKeyType::eKeyType_Method, "method"}
};
// 定义支持的业务数据
std::map<const char *, DoMethodVRetPStr* > MethodConfigs ={
{ "DoPrint", DoPrint},
{ "DoOthers", DoOthers}
};
// 解析接口 -- 获取方法
auto prt_Analyse_GetMethod = [&](const char* data)->DoMethodVRetPStr*
{
// 序列化解析
json requestJson = json::parse(data);
const char* key = KeyConfigs[EKeyType::eKeyType_Method];
std::string methodName = requestJson.value(key, "");
if (methodName == "")
return nullptr;
for (auto it : MethodConfigs)
{
if (methodName.compare(it.first) == 0)
return it.second;
}
return nullptr;
};
// 解析接口 -- 获取数据
auto prt_Analyse_GetData = [&](const char* data)->std::string
{
// 序列化解析
json requestJson = json::parse(data);
const char* key = KeyConfigs[EKeyType::eKeyType_Data];
return requestJson.value(key, "");
};
// 接口执行器
auto prt_Run = [&](const char* data)
{
DoMethodVRetPStr* handler = prt_Analyse_GetMethod(data);
std::string handerData = prt_Analyse_GetData(data);
// 当然可以直接执行
// handler(handerData.c_str());
// level4模式不过时,此处沿用
DataProtocol _setData = { handerData.c_str() , handler };
TestProtocol(_setData);
};
// 调用接口,执行业务
// 业务数据
const char* protocolRequest = R"(
{
"method": "DoPrint",
"data": "Level 5 TEST PROTOCAL "
}
)";
// 调用接口执行
prt_Run(protocolRequest);
Level 6 文本协议-- 扩充功能,添加逻辑流程控制
在level5 上添加一个loop控制个数参数
auto DoLoop = [](int loopCount, DataProtocol* hander) {
if (!hander)
return;
for (; loopCount > 0; loopCount--)
{
hander->m_handler(hander->m_para);
}
};
using LoopLogicType = void(int , DataProtocol*);
// 定义支持的业务数据,添加一个 Loop控制参数
std::map<std::string, LoopLogicType* > logicMethodConfigs = {
{ "loop", DoLoop}
};
auto prt_Analyse_GetLoop = [&](const char* data,int& outData) -> LoopLogicType*
{
json requestJson = json::parse(data);
std::string key = KeyConfigs[EKeyType::eKeyType_Loop];
if (requestJson.contains(key))
{
outData = requestJson.value(key,1);
for (auto it : logicMethodConfigs)
{
if (key.compare(it.first) != std::string::npos)
return it.second;
}
}
return nullptr;
};
// 接口执行器
auto prt_Run_extra = [&](const char* data)
{
DoMethodVRetPStr* handler = prt_Analyse_GetMethod(data);
std::string handerData = prt_Analyse_GetData(data);
DataProtocol _setData = { handerData.c_str() , handler };
int loopCount = 0;
LoopLogicType *loopMethod = prt_Analyse_GetLoop(data, loopCount);
if(loopMethod)
{
loopMethod(loopCount, &_setData);
}
};
// 输入业务数据
const char* protocolRequest_extra = R"(
{
"method": "DoPrint",
"data": "Level 6 TEST PROTOCAL extention , add Loop control",
"loop":3
}
)";
// 执行业务数据
prt_Run_extra(protocolRequest_extra);
Level 7 自定义脚本语法编译器,此处略过
// Leve7
// 自定义脚本语法编译器,例如以下脚本内容 ---此处代码略过不写了
const char* script = R"(
loopCount = 3
for i in range(0,loopCount){
print "Level7 run script"
}
)";
测试代码输出如下:
源码(需要nlohmann/json.hpp)
// DemoPPt.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "nlohmann/json.hpp"
#include <iostream>
using DoMethodVRetPStr = void(const char*);
using nlohmann::json;
const char* GetData(const char* data)
{
return data;
}
void DoPrint_Simple()
{
std::cout << "Level 1 无模式\n";
}
void DoOthers(const char* data)
{
return;
}
int main()
{
//Level 1
DoPrint_Simple();
//Level 2
// 方法
auto DoPrint = [](const char* data)
{
std::cout << data;
std::cout << "\n";
};
// 数据
const char* data = GetData("Level 2 简单模式,数据分离\n");
// 业务执行
DoPrint(data);
//Level 3
const char* data2 = GetData("Level 3 简单模式,数据与方法分离\n");
DoMethodVRetPStr *method1 = DoPrint;
method1(data2);
//Level 4
// 简单接口协议定义
struct DataProtocol
{
const char* m_para;
DoMethodVRetPStr* m_handler;
};
// 数据容器,存储支持的业务类型
DataProtocol testData[] = {
{"Level 4 简单协议模式", DoPrint},
{"...", DoOthers},
{nullptr, nullptr}
};
// 接口解析器
auto TestProtocol = [](DataProtocol& data) ->void
{
data.m_handler(data.m_para);
};
// 业务层调用接口,其他
TestProtocol(testData[0]);
//Level 5
// 使用文本协议定义
// 类似于http 文本协议,制定类似以下文本协议请求(此处借用json数据格式,现今数据格式众多,比如xml, protobuf, bson,)
// 当然也可以纯二进制协议(可参考UDP/TCP协议如何定义的,访问国际通用的RFC网站,https://datatracker.ietf.org/doc/rfc793/)
// 还可以文本与二进制混合的文本协议(http就是文本与二进制混合的协议,图片音视频都可以传输)
// 例如 const char* protocolRequest = "{ \"method\":\"DoPrint\",\"data\":\"通用定制化文本协议模式\" }";
// 定义接口协议
enum class EKeyType:int
{
eKeyType_Data = 0,
eKeyType_Method,
eKeyType_Loop
};
std::map<EKeyType, const char *> KeyConfigs = {
{EKeyType::eKeyType_Data,"data"},
{EKeyType::eKeyType_Loop,"loop"},
{EKeyType::eKeyType_Method, "method"}
};
// 定义支持的业务数据
std::map<const char *, DoMethodVRetPStr* > MethodConfigs ={
{ "DoPrint", DoPrint},
{ "DoOthers", DoOthers}
};
// 解析接口 -- 获取方法
auto prt_Analyse_GetMethod = [&](const char* data)->DoMethodVRetPStr*
{
// 序列化解析
json requestJson = json::parse(data);
const char* key = KeyConfigs[EKeyType::eKeyType_Method];
std::string methodName = requestJson.value(key, "");
if (methodName == "")
return nullptr;
for (auto it : MethodConfigs)
{
if (methodName.compare(it.first) == 0)
return it.second;
}
return nullptr;
};
// 解析接口 -- 获取数据
auto prt_Analyse_GetData = [&](const char* data)->std::string
{
// 序列化解析
json requestJson = json::parse(data);
const char* key = KeyConfigs[EKeyType::eKeyType_Data];
return requestJson.value(key, "");
};
// 接口执行器
auto prt_Run = [&](const char* data)
{
DoMethodVRetPStr* handler = prt_Analyse_GetMethod(data);
std::string handerData = prt_Analyse_GetData(data);
// 当然可以直接执行
// handler(handerData.c_str());
// level4模式不过时,此处沿用
DataProtocol _setData = { handerData.c_str() , handler };
TestProtocol(_setData);
};
// 调用接口,执行业务
// 业务数据
const char* protocolRequest = R"(
{
"method": "DoPrint",
"data": "Level 5 TEST PROTOCAL "
}
)";
prt_Run(protocolRequest);
// Level 6
// 使用文本协议定义 -- 扩充功能,添加逻辑流程控制
auto DoLoop = [](int loopCount, DataProtocol* hander) {
if (!hander)
return;
for (; loopCount > 0; loopCount--)
{
hander->m_handler(hander->m_para);
}
};
using LoopLogicType = void(int , DataProtocol*);
// 定义支持的业务数据
std::map<std::string, LoopLogicType* > logicMethodConfigs = {
{ "loop", DoLoop}
};
auto prt_Analyse_GetLoop = [&](const char* data,int& outData) -> LoopLogicType*
{
json requestJson = json::parse(data);
std::string key = KeyConfigs[EKeyType::eKeyType_Loop];
if (requestJson.contains(key))
{
outData = requestJson.value(key,1);
for (auto it : logicMethodConfigs)
{
if (key.compare(it.first) != std::string::npos)
return it.second;
}
}
return nullptr;
};
// 接口执行器
auto prt_Run_extra = [&](const char* data)
{
DoMethodVRetPStr* handler = prt_Analyse_GetMethod(data);
std::string handerData = prt_Analyse_GetData(data);
DataProtocol _setData = { handerData.c_str() , handler };
int loopCount = 0;
LoopLogicType *loopMethod = prt_Analyse_GetLoop(data, loopCount);
if(loopMethod)
{
loopMethod(loopCount, &_setData);
}
};
const char* protocolRequest_extra = R"(
{
"method": "DoPrint",
"data": "Level 6 TEST PROTOCAL extention , add Loop control",
"loop":3
}
)";
prt_Run_extra(protocolRequest_extra);
// Leve7
// 自定义脚本语法编译器,例如以下脚本内容 ---此处代码略过不写了
const char* script = R"(
loopCount = 3
for i in range(0,loopCount){
print "Level7 run script"
}
)";
return 1;
}