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;
}