思路介绍
网络版计算器:
1、客户端发送 两个操作数 和 操作符;
2、根据协议,在发送时,对数据进行序列化,再加上报头,形成 请求 并发送给 服务器;
3、服务器收到 请求 后,判断收到的 请求 是否完整;
4、若 请求 完整,则从 请求 中分离出有效载荷,再对有效载荷进行 反序列化;
5、服务器处理完数据后,把 结果 进行序列化,并加上报头,作为 应答 发送给客户端;
6、客户端判断收到的 应答 是否完整;
7、 应答 完整,对 应答 进行解析,从有效载荷中取出计算结果。
gitee
net_cal · zihuixie/Linux_Learning - 码云 - 开源中国https://gitee.com/zihuixie/linux_-learning/tree/master/net_cal
主要代码
序列化 && 反序列化 -- Protocol.hpp
#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\nstd::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;};
}