思路介绍
网络版计算器:
1、客户端发送 两个操作数 和 操作符;
2、根据协议,在发送时,对数据进行序列化,再加上报头,形成请求并发送给 服务器;
3、服务器收到 请求 后,判断收到的 请求 是否完整;
4、若 请求 完整,则从 请求 中分离出有效载荷,再对有效载荷进行 反序列化;
5、服务器处理完数据后,把 结果 进行序列化,并加上报头,作为应答发送给客户端;
6、客户端判断收到的 应答 是否完整;
7、 应答 完整,对 应答 进行解析,从有效载荷中取出计算结果。
gitee
主要代码
序列化 && 反序列化 -- Protocol.hpp
cpp
#pragma once
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
#include <unistd.h>
#include<memory>
//指定协议
namespace protocol_ns
{
const std::string SEP = "\r\n"; // 分隔符
// 添加报头(有效载荷已经序列化)
// 报文:len\r\n{ }\r\n
std::string Encode(const std::string &json_str)
{
int json_str_len = json_str.size(); // 计算长度
std::string proto_str = std::to_string(json_str_len); // 报文
proto_str += SEP; // 分隔符
proto_str += json_str; // 有效载荷
proto_str += SEP;
return proto_str;
}
// len\r\n{
// len\r\n{ }
// len\r\n{ }\r\n
// len\r\n{ }\r\nlen\r\n{
// len\r\n{ }\r\nlen\r\n{ }\r
// len\r\n{ }\r\nlen\r\n{ }\r\n
// len\r\n{ }\r\nlen\r\n{ }\r\nlen\r
// len\r\n{ }\r\nlen\r\n{ }\r\nlen\r\n{ }\r\n
// 分离出有效载荷(但收到的报文不一定是完整的,判断收到的报文中有一个完整的报文,就可以进行分离)
std::string Decode(std::string &inbuffer)
{
auto pos = inbuffer.find(SEP);
// 报文不完整
if (pos == std::string::npos)
return std::string();
std::string len_str = inbuffer.substr(0, pos);
if (len_str.empty())
return std::string();
int packlen = std::stoi(len_str); // 有效载荷的长度
int total = packlen + 2 * SEP.size() + len_str.size(); // 完整报文的长度
if (inbuffer.size() < total)
return std::string(); // 不是完整报文
std::string package = inbuffer.substr(pos + SEP.size(), packlen); // 有效载荷
inbuffer.erase(0, total); // 在报文中去掉完整的一段,避免重复处理
return package;
}
// 请求,客户端向服务器发送请求
class Request
{
public:
Request()
{
}
Request(int x, int y, char oper)
: _x(x), _y(y), _oper(oper)
{
}
// 序列化,out 是输出型参数
// 客户端发送请求时,将请求序列化
bool Serialize(std::string *out)
{
Json::Value root;
root["x"] = _x;
root["y"] = _y;
root["oper"] = _oper;
Json::FastWriter writer;
*out = writer.write(root); // 将 root 序列化为字符串
return true;
}
// 反序列化
// 服务器收到请求,将请求反序列化
bool Deserialize(const std::string &in)
{
Json::Value root;
Json::Reader reader; // 从字符串中读取 Json 数据
bool res = reader.parse(in, root); // 解析
// 解析失败
if (!res)
return false;
// 解析成功
_x = root["x"].asInt();
_y = root["y"].asInt();
_oper = root["oper"].asInt();
return true;
}
public:
int _x; // 左操作数
int _y; // 右操作数
char _oper; // 操作符
};
// 应答
// 服务器处理完请求,向客户端发送应答
class Response
{
public:
Response()
{
}
Response(int result, int code)
: _result(result), _code(code)
{
}
// 序列化,out 是输出型参数
// 将应答序列化,发送给客户端
bool Serialize(std::string *out)
{
Json::Value root;
root["result"] = _result;
root["code"] = _code;
Json::FastWriter writer;
*out = writer.write(root); // 将 root 序列化为字符串
return true;
}
// 反序列化
// 客户端收到应答,将应答反序列化
bool Deserialize(const std::string &in)
{
Json::Value root;
Json::Reader reader; // 从字符串中读取 Json 数据
bool res = reader.parse(in, root); // 解析
// 解析失败
if (!res)
return false;
// 解析成功
_result = root["result"].asInt();
_code = root["code"].asInt();
return true;
}
public:
int _result; // 运算结果
int _code; // 结果是否可信,0:可信,1:除0,2:非法操作
};
// 工厂,创造数据
// 模拟客户端
class Factory
{
public:
Factory()
{
srand(time(nullptr) ^ getpid());
opers = "+/*/%^&|";
}
std::shared_ptr<Request> BuildRequest()
{
int x = rand() % 10 + 1;
usleep(x * 10);
int y = rand() % 5;
usleep(y * x * 5);
char oper = opers[rand() % opers.size()];
std::shared_ptr<Request> req = std::make_shared<Request>(x, y, oper);
return req;
}
std::shared_ptr<Response> BuildResponse()
{
return std::make_shared<Response>();
}
~Factory()
{
}
private:
std::string opers;
};
}