该文件实现序列化与反序列使用到的类和相关函数(加报头解报头)!
1.1 Request类
1.1.1 基本结构
该类有三个成员变量,_x,_y,_oper(运算符号),序列化,反序列化,构造,析构及其他获取成员变量与打印的函数!
namespace protocol{
class Request{
public:
Request(){}
// 序列化 将结构化转成字符串
bool Serialize(std::string& out);
// 反序列化 将字符串转成结构化
bool Deserialize(const std::string& in);
void Print();
int X();
int Y();
char Oper();
~Request(){}
private:
int _x;
int _y;
char _oper; // 计算符号
};
}
1.1.2 构造、析构函数
为了方便后面的使用,此处实现两个构造函数,一个无参,一个带参函数,析构函数无需处理!
// 构造函数 - 无参
Request() {}
// 构造函数 - 有参
Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper) {}
// 析构函数
~Request(){}
1.1.3 序列化函数
序列化即将结构化转成字符串,并将字符串以输出型参数输出
// 序列化 将结构化转成字符串
bool Serialize(std::string* out){
// 使用现成的库,xml,json,protobuf等
// 这里使用json库
Json::Value root;
root["x"] = _x;
root["y"] = _y;
root["oper"] = _oper;
Json::FastWriter writer;
std::string s = writer.write(root);
*out = s;
return true;
}
1.1.4 反序列化函数
反序列化即将字符串转成结构化,参数传入字符串!
// 反序列化 将字符串转成结构化
bool Deserialize(const std::string& in) {
Json::Value root;
Json::Reader reader;
bool res = reader.parse(in, root);
_x = root["x"].asInt();
_y = root["y"].asInt();
_oper = root["oper"].asInt();
return true;
}
1.1.5 其他函数
void Print() {
std::cout << _x << std::endl;
std::cout << _y << std::endl;
std::cout << _oper << std::endl;
}
int X() { return _x; }
int Y() { return _y; }
char Oper() { return _oper; }
void SetValue(int x, int y, char oper) {
_x = x;
_y = y;
_oper = oper;
}
1.2、Response类
1.2.1 基本结构
这个类我们需要组织发送给客户端的响应,需要三个成员变量,_result(计算结果),_code(自定义错误码),_desc(错误码描述)
内部主要是 序列化(发送)
和 反序列化(接受)
函数!
class Response {
public:
Response() : _result(0), _code(0), _desc("success") {}
bool Serialize(std::string* out);
bool Deserialize(const std::string& in);
~Response() {}
public:
int _result;
int _code; // 错误码 0 success, 1 fail, 2 fatal
std::string _desc; // 错误码描述
};
1.2.2 构造析构函数
构造函数直接手动初始化(结果和错误码初始化为0,描述默认初始化为success)
析构函数无需处理!
Response() : _result(0), _code(0), _desc("success") {}
~Response() {}
1.2.3 序列化函数
这里和 request
类如出一辙,只需要构造相应的JSON结果,然后利用紧凑方法,构造出JSON风格的字符串就行了
bool Serialize(std::string* out) {
Json::Value root;
root["result"] = _result;
root["code"] = _code;
root["desc"] = _desc;
Json::FastWriter writer;
std::string s = writer.write(root);
*out = s;
return true;
}
1.2.4 反序列化函数
反序列化即将字符串转成结构化,参数传入字符串!
// 反序列化 - 将JSON字符串反序列化成成员变量
bool Deserialize(const std::string& in) {
Json::Value root;
Json::Reader reader;
// parse 的作用是将 JSON 字符串解析成 Json::Value 对象
bool res = reader.parse(in, root);
_result = root["result"].asInt();
_code = root["code"].asInt();
_desc = root["desc"].asString();
return true;
}
1.2.5 打印结果
将成员变量以字符串形式打印出来即可!
void PrintResult(){
std::cout << "result: " << _result << ", code: " << _code
<< ", desc: " << _desc << std::endl;
}
1.3 Factory类
- 因为
Request类
和Response类
可能频繁创建,因此我们可以设计一个工厂类,内部设计两个创建类的静态函数(没有this指针,外部直接调用函数即可)!
class Factory {
public:
static std::shared_ptr<Request> BuildRequestDefault() {
return std::make_shared<Request>();
}
static std::shared_ptr<Response> BuildResponseDefault() {
return std::make_shared<Response>();
}
};
1.4 报头
在实际的网络通信中,传的不仅仅是序列化后的字符串,还有报头信息,此处我们也设计一下报头信息
-
"len"\r\n"{json}"\r\n
– 完整的报文 - len 有效荷载长度
-
\r\n
(第一个):区分 len 和 json 串 -
\r\n
(第二个):暂时没用
1.4.1 添加报头
// 添加报头
std::string AddHeader(const std::string& jsonstr) {
int len = jsonstr.size();
std::string lenstr = std::to_string(len);
return lenstr + sep + jsonstr + sep;
}
1.4.2 解析报头
注意:可能没有一个有效信息或者有多个有效信息!
// 解析报头
// 去掉前面的长度和分隔符与有效信息后面的分隔符
std::string ParseHeader(std::string& jsonstr) {
// 分析
auto pos = jsonstr.find(sep); // 在json风格字符串中找第一个分隔符
if (pos == std::string::npos)
return std::string(); // 找不到分隔符,返回空字符串
// 获取 len
std::string lenstr = jsonstr.substr(0, pos); // 取出长度字符串
int len = std::stoi(lenstr); // 转成整数
// 计算一个完整的报文应该是多长
int totallen = lenstr.size() + len + 2 * sep.size();
// 若传进来的字符串长度小于报文总长,说明没有一个完整的有效信息,返回空
if (jsonstr.size() < totallen)
return std::string();
// 取出有效信息
std::string validstr = jsonstr.substr(pos + sep.size(), len);
// 去掉最后的分隔符
jsonstr.erase(0, totallen);
return validstr;
}