应用层自定义协议、序列化和反序列化

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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;这并不是个体问题&…