應用層自定義協議、序列化和反序列化

1.自定義協議

開發者根據特定應用場景的需要,自行設計和制定的通信規則和數據格式??

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/98529.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/98529.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/98529.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Excel VBA 中可用的工作表函數

Visual Basic for Applications (VBA) 中可用的工作表函數。可以在 VBA 中通過 Application.WorksheetFunction 對象調用。 下面我將按照字母分組&#xff0c;對每個函數進行簡要解釋&#xff0c;并給出在 VBA 中使用的示例。A 組Acos: 返回數字的反余弦值。 result Applicati…

OpenWrt + Docker 完整部署方案:CFnat + Cloudflared 一體化集成

AI生成&#xff08;可能是AI幻覺&#xff09; 項目架構概述 基于您現有的網絡配置&#xff08;IP: 192.168.1.1&#xff09;&#xff0c;本方案將CFnat服務作為網絡優化層整合到現有的Cloudflare隧道架構中&#xff0c;實現完整的網絡加速解決方案。 優化后的流量路徑 用戶訪問…

蒼穹外賣項目實戰(day7-1)-緩存菜品和緩存套餐功能-記錄實戰教程、問題的解決方法以及完整代碼

完整資料下載 通過網盤分享的文件&#xff1a;蒼穹外賣 鏈接: https://pan.baidu.com/s/1JJaFOodXOF_lNJSUiZ6qtw?pwdps2t 提取碼: ps2t 目錄 1、緩存菜品 &#xff08;1&#xff09;問題說明 &#xff08;2&#xff09;使用redis緩存部分數據 1-2、代碼完善 &#xff…

計算機畢業設計 基于Python+Django的醫療數據分析系統

精彩專欄推薦訂閱&#xff1a;在 下方專欄&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主頁&#xff1a;計算機畢設木哥&#x1f525; &#x1f496; 文章目錄 一、項目介紹二…

使用 chromedp 高效爬取 Bing 搜索結果

在數據采集領域&#xff0c;搜索引擎結果是重要的信息來源。但傳統爬蟲面對現代瀏覽器渲染的頁面時&#xff0c;常因 JavaScript 動態加載、跳轉鏈接加密等問題束手無策。本文將詳細介紹如何使用 Go 語言的chromedp庫&#xff0c;模擬真實瀏覽器行為爬取 Bing 搜索結果&#xf…

遺漏的需求

“編寫執行者的目的&#xff0c;僅用別名來表達需要傳遞的數據”&#xff0c;就如客戶信息用名字和地址表示一樣&#xff0c;這是一個很好的建議。然而&#xff0c;對程序員來說&#xff0c;這沒有提供軟件開發所必需的詳細信息。程序設計人員和用戶界面設計者需要準確地知道地…

《云原生故障診療指南:從假活到配置漂移的根治方案》

當云原生架構成為企業數字化轉型的標配,系統故障的形態也隨之發生了根本性變化。曾經那些“一目了然”的報錯信息逐漸消失,取而代之的是“指標正常卻服務不可用”“偶發故障無規律可循”等隱性問題。這些故障如同架構中的“暗物質”,看不見卻持續影響著系統的穩定性,其排查…

“從零到一:使用GitLab和Jenkins實現自動化CI/CD流水線”

GitLab倉庫 簡單的來說就是開發人員提交代碼的倉庫&#xff0c;用于團隊開發&#xff0c;GitLab 上托管的倉庫通常作為遠程倉庫使用&#xff0c;開發人員可以將本地的 Git 倉庫推送到 GitLab 上&#xff0c;也可以從 GitLab 克隆倉庫到本地進行開發。 Jenkins Jenkins 是一個開…

3D開發工具HOOPS助力造船業數字化轉型,打造更高效、更智能的船舶設計與協作!

造船業是一個高度復雜且競爭激烈的行業&#xff0c;涵蓋船體設計、結構分析、生產制造到運維管理的完整生命周期。面對龐大的CAD數據、多方協作的復雜流程以及數字化轉型的迫切需求&#xff0c;傳統工具往往顯得力不從心。 Tech Soft 3D的HOOPS SDK系列&#xff0c;正以其卓越…

Python調用MCP:無需重構,快速為現有應用注入AI與外部服務能力!

文章目錄 ?? 介紹 ?? ?? 演示環境 ?? ? MCP核心概念:AI世界的“USB-C” ? ??? MCP安裝與基礎使用 ??? ?? 安裝模塊 ?? 創建第一個MCP服務端 ?? Python中MCP客戶端的調用方案 ?? ?? 概述 ?? 深度解析 ?? 參數詳情 ?? 常用方法 ?? 不同傳輸協…

【鏈表】3.重排鏈表(medium)

重排鏈表&#xff08;medium&#xff09;題?描述&#xff1a;解法&#xff1a;算法思路&#xff1a;算法代碼&#xff1a;題?鏈接&#xff1a;143. 重排鏈表 題?描述&#xff1a; 給定?個單鏈表 L 的頭節點 head &#xff0c;單鏈表 L 表?為&#xff1a; L(0) → L(1) →…

蜜罐平臺-Hfish部署

Hfish簡介&#xff1a; HFish是一款社區型免費蜜罐&#xff0c;側重企業安全場景&#xff0c;從內網失陷檢測、外網威脅感知、威脅情報生產三個場景出發&#xff0c;為用戶提供可獨立操作且實用的功能&#xff0c;通過安全、敏捷、可靠的中低交互蜜罐增加用戶在失陷感知和威脅…

docker-容器

安裝docker yum install -y docker查看版本 docker version安裝docker-compose yum install -y docker-compose查看版本 docker-compose --version基礎鏡像構建 tar --exclude/var/lib -cvf euler.tar /etc /boot /var /tmp /usr /mnt /bin /sbin /lib /lib64將JDK等需要的中間…

ESP32開發:ubuntu22.04 下esp-idf開發環境搭建

ubuntu22.04 下 esp-idf 開發環境搭建1.安裝編譯 ESP-IDF 需要以下軟件包2.獲取 ESP-IDF3.設置工具下載工具備選方案4.設置環境變量5.編譯工程并燒錄配置工程編譯工程燒錄固件到設備6.其他指令監視輸出擦除 flash清除編譯1.安裝編譯 ESP-IDF 需要以下軟件包 編譯 ESP-IDF 需要…

匯編基礎2

1.函數調用fun0mov r4, #100bx lrget_MaxNumcmp r0, r1stmfd sp!, {r0-r12, lr} //入棧bl fun0 //調用fun0函數ldmfd sp!, {r0-r12, lr} //出棧movge r3, r0movlt r3, r1bx lr mainldr sp, 0x40001000mov r0, #100mov r1, #200mov r2, #100stmfd sp!,…

20250909的學習筆記

HTML 基礎筆記1. HTML 基本格式<!DOCTYPE html> <html> <head><meta charset"utf-8"><title>中文測試</title> </head> <body>這里是測試body測試內容。 </body> </html>2. HTML 標簽常用標簽 - <h1…

Linux 安全加固;Windows 安全設置

一、Linux 安全加固1. 賬戶與權限管理最小權限原則禁用 root 遠程登錄&#xff1a;修改 /etc/ssh/sshd_config&#xff0c;設置 PermitRootLogin no。使用 sudo 替代直接 root 操作&#xff0c;并通過 /etc/sudoers 限制命令范圍&#xff08;如僅允許 apt 和 systemctl&#xf…

條碼打印檢測一體機是什么?

在工業4.0和智能制造的大背景下&#xff0c;數據的準確性和實時性是構建高效追溯系統。條碼/二維碼作為物理世界與數字世界連接的橋梁&#xff0c;其打印質量直接決定了數據鏈路的可靠性。傳統“打印-人工抽檢/離線全檢”的模式存在流程割裂、效率低下、無法100%覆蓋的弊端&…

Javaweb - 14.6 - Vue3 數據交互 Axios

目錄 Promise 普通函數和回調函數 Promise 簡介 Promise 基本用法 async 和 await 的使用 Axios 介紹 Axios 入門案例 Axios 的 get 和 post 方法 Axios 攔截器 完&#xff01; Promise 普通函數和回調函數 普通函數&#xff1a;正常調用的函數&#xff0c;一般函數…

怎么選適合企業的RPA財務機器人?

對于大多數財務人來說&#xff0c;“月初月末就是噩夢”已經成了常態&#xff1a;一邊要面對堆積如山的單據和報表&#xff0c;一邊還要應付領導不斷加碼的工作&#xff0c;常常忙到深夜&#xff0c;卻總覺得自己陷在重復事務中難有成長。其實&#xff0c;這并不是個體問題&…