我们网络收发数据实际上只能接收到字符串,但是在现实生活中描述一个客观物体都是以很多属性来描述的,所以在网络中结构体类型的数据更常见,那我们如何发送结构体数据呢?
这里就涉及到协议的概念了。我们想象一个场景,在特种兵执行任务时,他们有特定的战术手语,这样他们就能根据手语进行相应的战术配合了。所以协议也是一样,客户端和服务器都遵循相同的协议,以某种格式把字符串变成结构体或把结构体变成字符串。这个过程中就是序列化与反序列化。
序列化:结构体类型数据转化成字节序
反序列化:字节序转化成结构体类型数据
话不多说,看图
服务器利用套接字接收请求,进行反序列化后,对请求进行业务处理,处理完成把结果生成响应
然后序列化发送给客户端。自然,客户端接收响应也必须反序列化。
简易网络计算器协议协议部分代码:定制自己的协议,确定数据格式。
下面还利用到了Json这种数据转换格式语言。
- #pragma once
-
- #include
- #include
- #include "Util.hpp"
- #include
- #include
- // 利用条件编译,在这里定义一个宏,如果定义了就走a,否则就走b,这相当于是一个开关
-
- // #define HAHA 666
- // 给网络版本计算器制定协议
- namespace Protocol_ns
- {
-
- #define SEP " "
- #define SEP_LEN strlen(SEP) // 不能用sizeof
- #define HEADER_SEP "\r\n"
- #define HEADER_SEP_LEN strlen("\r\n")
-
- // 请求/响应 = 报头\r\n有效载荷\r\n
-
- // "10 + 20" => "7"\r\n""10 + 20"\r\n
- std::string AddHeader(std::string &str)
- {
- std::string s = std::to_string(str.size());
-
- s += HEADER_SEP;
- s += str;
- s += HEADER_SEP;
- return s;
- }
-
- // 读取一个完整的报文;
- int ReadPackage(int sock, std::string &inbuffer, std::string *package)
- {
-
- char buffer[1024];
- ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0); // 读取
- if (n <= 0)
- return -1;
- buffer[n] = 0; // 添加字符串末尾'/0';
- inbuffer += buffer;
-
- size_t pos = inbuffer.find(HEADER_SEP);
- if (pos == std::string::npos)
- return 0; // 虽然读到了数据,但是不存在一个完整的报文,应该继续读取
-
- std::string lenStr = inbuffer.substr(0, pos);
- int len = Util::toInt(lenStr);
- int targetPackageLen = HEADER_SEP_LEN * 2 + len + lenStr.size();
- if (inbuffer.size() < targetPackageLen)
- return 0; // 虽然读到了数据,但是不存在一个完整的报文,应该继续读取
-
- *package = inbuffer.substr(0, targetPackageLen); // 提取到了整个报文
- inbuffer.erase(0, targetPackageLen); // 从inbuffer中直接移除整个报文
-
- return len; // 返回有效载荷长度
- }
-
- // "7"\r\n""10 + 20"\r\n => "10 + 20"
- void RemoveHeader(std::string *package, int len)
- {
- size_t pos = (*package).find(HEADER_SEP);
- *package = (*package).erase(0, pos);
-
- *package = (*package).erase(0, HEADER_SEP_LEN);
-
- *package = (*package).substr(0, len);
- }
-
- // Request && Response都要提供序列化和反序列化功能
- class Request
- {
- public:
- Request() {}
-
- Request(int x, int y, char op)
- : _x(x), _y(y), _op(op)
- {
- }
-
- // struct -> string
- bool Serialization(std::string *outStr)
- {
- *outStr = "";
- #ifdef HAHA
-
- std::string x_string = std::to_string(_x);
- std::string y_string = std::to_string(_y);
-
- // 手动序列化
- *outStr = x_string + SEP + _op + SEP + y_string; // outstr在这里是输出型参数;
- #else
- Json::Value root; // Value: 一种万能对象, 接受任意的kv类型
-
- root["x"] = _x;
- root["y"] = _y;
- root["op"] = _op;
-
- Json::StyledWriter writer; // Writer是用来进行序列化的,struct->string
- *outStr = writer.write(root);
-
- #endif
- return true;
- }
-
- // string->struct
- bool Deserialization(const std::string &inStr)
- {
- #ifdef HAHA
-
- std::vector
result; - Util::StringSplit(inStr, SEP, &result); // 对序列化数据进行分割,这相当于是一种解释;
- if (result.size() != 3)
- return false;
- if (result[1].size() != 1)
- return false;
-
- _x = Util::toInt(result[0]);
- _y = Util::toInt(result[2]);
- _op = result[1][0];
- #else
- Json::Value root;
- Json::Reader reader; // Reader:用来进行反序列化的。
-
- reader.parse(inStr, root);
- _x = root["x"].asInt();
- _y = root["y"].asInt();
- _op = root["op"].asInt();
-
- #endif
- return true;
- }
-
- ~Request() {}
-
- public:
- int _x;
- int _y;
- char _op;
- };
-
- class Response
- {
- public:
- Response() {}
-
- Response(int result, int code)
- : _result(result), _code(code)
- {
- }
-
- bool Serialization(std::string *outStr)
- {
-
- *outStr = "";
- #ifdef HAHA
- std::string _result_string = std::to_string(_result);
- std::string _code_string = std::to_string(_code);
-
- // 手动序列化
- *outStr = _result_string + SEP + _code_string; // outstr在这里是输出型参数;
-
- #else
- Json::Value root;
- root["result"] = _result;
- root["code"] = _code;
-
- Json::StyledWriter writer; // writer::用来进行序列化的;
-
- *outStr = writer.write(root);
-
- #endif
- return true;
- }
-
- bool Deserialization(const std::string &inStr)
- {
- #ifdef HAHA
- std::vector
result; - Util::StringSplit(inStr, SEP, &result); // 对序列化数据进行分割,这相当于是一种解释;
- if (result.size() != 2)
- return false;
-
- _result = Util::toInt(result[0]);
- _code = Util::toInt(result[1]);
- #else
- Json::Value root;
- Json::Reader reader;
-
- reader.parse(inStr,root);
- _result=root["result"].asInt();
- _code=root["code"].asInt();
-
-
- #endif
- return true;
- }
-
- ~Response() {}
-
- public:
- int _result;
- int _code; // 0 success, 1,2,3,4代表不同的错误码;
- };
- }