1.自定义协议
开发者根据特定应用场景的需要,自行设计和制定的通信规则和数据格式
1.1 核心组成部分
一个典型的自定义协议通常包含以下几个关键部分:
帧/报文格式 (Frame/Packet Format):定义了数据是如何打包的。这通常包括:
- 魔数 (Magic Number):一个特殊的标识符,用于快速识别数据包的开始或验证协议类型。
- 包头 (Header):包含元数据,如版本号、数据包类型、包体长度、序列号等。
- 包体 (Body/Payload):实际要传输的有效数据。
- 校验和 (Checksum):用于检验数据在传输过程中是否出错(如 CRC32)
1.2 有关网络计算器的自定义协议
#pragma once
#include<iostream>
#include"Socket.hpp"
#include<string>
#include<memory>
#include<jsoncpp/json/json.h>
#include<functional>
using namespace std;
class Request //请求
{
public:
Request()
{
}
Request(int x, int y, char oper): _x(x), _y(y), _oper(oper)
{
}
std::string Serialize() //实现序列化
{
Json::Value root;
root["x"] = _x;
root["y"] = _y;
root["oper"] = _oper;
Json::FastWriter writer;
return writer.write(root);
}
bool Deserialize(std::string &in) //实现反序列化
{
Json::Value root;
Json::Reader reader;
bool ok = reader.parse(in,root);
if(!ok)
{
return false;
}
_x = root["x"].asInt();
_y = root["y"].asInt();
_oper = root["oper"].asInt();
}
~Request(){}
int X() { return _x; }
int Y() { return _y; }
char Oper() { return _oper; }
private:
int _x;
int _y;
char _oper;
};
class Response //应答
{
public:
Response(){};
Response(int result,int code):_result(result),_code(code)
{
}
std::string Serialize() //序列化
{
Json::Value root;
root["result"] = _result;
root["code"] = _code;
Json::FastWriter writer;
return writer.write(root);
}
bool Deserialize(std::string &in) //反序列化
{
Json::Value root;
Json::Reader reader;
bool ok = reader.parse(in,root);
if(!ok)
{
return false;
}
_result = root["result"].asInt();
_code = root["code"].asInt();
return true;
}
~Response(){};
int setResult() { return _result; }
int setCode() { return _code; }
private:
int _result;
int _code;
};
const std::string sep = "\r\n"; //报文的分隔符
using func_t = std::function<Response(Request &req)>; //func_t为自定义类型
class Protocol
{
public:
Protocol() {}
Protocol(func_t func){}
string encode(string &in) //封装报文
{
int len =in.size();
string out = std::to_string(len) + sep + in+ sep;
return out;
}
bool decode(string &buffer,string& package) //解析报文(首先得判断收到的报文是否完整)
{
auto pos = buffer.find(sep);
if(pos == string::npos)
{
return false;
}
string len_str = buffer.substr(0,pos); //len_str为长度字段的字符串表示
int len = atoi(len_str.c_str()); //数据部分的字节大小
int tatoal_len = len_str.size() + len +2*sep.size(); //len_str.size()长度字段字符串的字节大小
if(buffer.size() < tatoal_len)
{
return false;
}
package = buffer.substr(pos+sep.size(),len);
buffer.erase(0,tatoal_len);
return true;
}
void GetRequest(std::shared_ptr<Socket> &sock, InetAddr &client) //获取请求
{
string buffer_queue;
while(true)
{
int n = socket->Recv(&buffer_queue);
if(n>0)
{
std::cout << "-----------request_buffer--------------" << std::endl;
std::cout << buffer_queue << std::endl;
std::cout << "------------------------------------" << std::endl;
while(decode(buffer_queue,&package))
{
Request req;
bool ret = req.Deserialize(package);
if(!ret)
{
std::cout << "Deserialize failed" << std::endl;
continue;
}
Response rsp = _func(req);
string rsp_str = rsp.Serialize();
string out = encode(rsp_str);
socket->Send(out);
}
}
else if(n == 0)
{
std::cout << "client quit" << std::endl;
socket->Close();
break;
}
else
{
if(errno == EAGAIN || errno == EWOULDBLOCK)
{
std::cout << "data over" << std::endl;
break;
}
std::cout << "recv error" << std::endl;
socket->Close();
break;
}
}
}
void Getresponse(std::shared_ptr<Socket> &sock) //获取应答
{
string buffer_queue;
while(true)
{
int n = socket->Recv(&buffer_queue);
if(n>0)
{
std::cout << "-----------response_buffer--------------" << std::endl;
std::cout << buffer_queue << std::endl;
std::cout << "------------------------------------" << std::endl;
while(decode(buffer_queue,&package))
{
Response rsp;
bool ret = rsp.Deserialize(package);
if(!ret)
{
std::cout << "Deserialize failed" << std::endl;
continue;
}
std::cout << "result: " << rsp.setResult() << " code: " << rsp.setCode() << std::endl;
}
}
else if(n == 0)
{
std::cout << "server quit" << std::endl;
socket->Close();
break;
}
else
{
if(errno == EAGAIN || errno == EWOULDBLOCK)
{
std::cout << "data over" << std::endl;
break;
}
std::cout << "recv error" << std::endl;
socket->Close();
break;
}
}
}
string BuildRequest(int x, int y, char oper) //封装请求的报文
{
Request req(x,y,oper);
string req_str = req.Serialize();
string out = encode(req_str);
return out;
}
~Protocol() {}
private:
func_t _func;
std::shared_ptr<Socket> socket;
string package;
string buffer_queue;
};
2.序列化和反序列化
序列化和反序列化都是发生在应用层
序列化和反序列化的核心作用是解决数据在【内存中的对象】与【可传输/存储的格式】之间相互转换的问题,简要来说就是方便数据的传输,在上面的自定义协议中就运用了序列化和反序列化
为了方便实现序列化和反序列化,我们可以用Jsoncpp(用于处理JSON数据的C++库)
2.1 序列化
序列化指的是将数据结构或对象转换为一种格式,以便在网络上传输或存储到文件
中。Jsoncpp 提供了多种方式进行序列化:
1.使用 Json::Value 的 toStyledString 方法:
优点:将 Json::Value 对象直接转换为格式化的 JSON 字符串
示例:
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
int main()
{
Json::Value root;
root["name"] = "joe";
root["sex"] = "男";
std::string s = root.toStyledString();
std::cout << s << std::endl;
return 0;
}
$ ./test.exe
{
"name" : "joe",
"sex" : "男"
}
2.使用 Json::StreamWriter:
优点:提供了更多的定制选项,如缩进、换行符等
示例:
#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>
int main()
{
Json::Value root;
root["name"] = "joe";
root["sex"] = "男";
Json::StreamWriterBuilder wbuilder; // StreamWriter 的
工厂
std::unique_ptr<Json::StreamWriter>
writer(wbuilder.newStreamWriter());
std::stringstream ss;
writer->write(root, &ss);
std::cout << ss.str() << std::endl;
return 0;
}
$ ./test.exe
{
"name" : "joe",
"sex" : "男"
}
3.使用 Json::FastWriter
优点:比 StyledWriter 更快,因为它不添加额外的空格和换行符
#include <sstream>
#include<iostream>
#include<string>
#include <memory>
#include <jsoncpp/json/json.h>
int main()
{
Json::Value root;
root["name"] = "joe";
root["sex"] = "男";
Json::FastWriter writer;
std::string s = writer.write(root);
std::cout << s << std::endl;
return 0;
}
$ ./test.exe
{"name":"joe","sex":"男"}
#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>
int main()
{
Json::Value root;
root["name"] = "joe";
root["sex"] = "男";
// Json::FastWriter writer;
Json::StyledWriter writer;
std::string s = writer.write(root);
std::cout << s << std::endl;
return 0;
}
2.2 反序列化
反序列化指的是将序列化后的数据重新转换为原来的数据结构或对象。只需要学会Json::Reader即可,以下是示例:
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
int main() {
// JSON 字符串
std::string json_string = "{\"name\":\"张三\",
\"age\":30, \"city\":\"北京\"}";
// 解析 JSON 字符串
Json::Reader reader;
Json::Value root;
// 从字符串中读取 JSON 数据
bool parsingSuccessful = reader.parse(json_string,
root);
if (!parsingSuccessful) {
// 解析失败,输出错误信息
std::cout << "Failed to parse JSON: " <<
reader.getFormattedErrorMessages() << std::endl;
return 1;
}
// 访问 JSON 数据
std::string name = root["name"].asString();
int age = root["age"].asInt();
std::string city = root["city"].asString();
// 输出结果
std::cout << "Name: " << name << std::endl;
std::cout << "Age: " << age << std::endl;
std::cout << "City: " << city << std::endl;
return 0;
}