当前位置: 首页 > news >正文

Linux网络:序列化和反序列化

文章目录

  • 一,序列化和反序列化的概念理解
    • 1-1 在编程世界里的具体含义
    • 1-2 序列化 (打包)
    • 1-3 反序列化 (拆包组装)
    • 1-4 序列化和反序列化有什么意义
  • 二,序列化和反序列化
    • 2-1 简单的序列化示例
    • 2-1 简单的反序列化示例


一,序列化和反序列化的概念理解

  • 序列化就是你打包的过程

    • 你有一个复杂的物件,比如一辆自行车。你不能直接把整辆自行车塞进箱子。你需要把它拆解成车把、轮子、车架等部件,然后用泡沫纸包好,整齐地、扁平地放进一个纸箱里,最后在箱子上贴好标签“自行车-零件”。

    • 目的: 为了便于运输或储存。打包后的箱子规整、安全,方便卡车运送。

  • 反序列化就是你在新家拆包组装的过程

    • 你收到这个写着“自行车-零件”的箱子,然后根据之前的拆卸方法(或者箱子里的说明书),把零件重新组装起来,恢复成一辆可以骑的完整自行车

    • 目的: 将运输来的东西恢复原状,重新投入使用。


1-1 在编程世界里的具体含义

  • 在计算机中,程序运行时,数据(比如一个游戏角色的信息:名字、等级、血量、坐标)是以一种复杂的、存在于内存中的结构形式存在的。

  • 比如在C++里,它可能是一个结构体(struct)或一个对象(object),它们在内存中有特定的布局和指针关系。

  • 内存中的游戏角色对象 (复杂结构)

name: "Alice" (指向一个字符串的地址)
level: 99
health: 100.5
position: {x: 10.3, y: 20.8} (一个嵌套的结构)

现在,你想把这个角色的数据通过网络发送给另一个玩家,或者保存到硬盘上的一个文件里

问题来了:
你不能直接把内存里这一块地址(比如0x7ffeea6b8c10)通过网络发送出去,或者原样写入文件。因为:

  • 内存地址对其他机器或程序毫无意义。

  • 数据中可能包含指针指针的值在另一台机器上指向的可能是无效甚至危险的内容。

  • 不同的电脑可能有不同的字节序大端/小端,对数据的解释方式不同。

解决方案就是:序列化和反序列化


1-2 序列化 (打包)

过程: 将内存中这个结构化的对象,转换成一个平坦的、连续的字节序列(通常是一个字节流或一个字符串)。

这个字节序列是自描述的,可以被安全地传输或存储。

常用的“打包规则”(序列化格式)有:

  • JSON: {"name": "Alice", "level": 99, "health": 100.5, "position": {"x": 10.3, "y": 20.8}} 人类可读,非常流行。

  • XML: 类似HTML标签,稍微冗长。

  • Protocol Buffers (protobuf): Google发明的,二进制格式,体积小,速度快。

  • MessagePack: 二进制的JSON,比JSON体积小。

形象化: 你把那辆自行车(对象)拆解,按照JSON的说明书,打包成了一个贴有“JSON格式”标签的纸箱(一串字节流)。


1-3 反序列化 (拆包组装)

过程: 当另一端收到这个字节流(或从文件读取后),它需要根据相同的规则,将这个字节序列重新构建成内存中一个全新的、和原始对象一模一样的结构化对象

形象化: 对方收到“JSON格式”的纸箱,按照JSON的说明书,把零件重新组装成了那辆完全可以正常骑行的“自行车”(对象)。


1-4 序列化和反序列化有什么意义

在我们之前学习socket编程中中:

  • 客户端发送数据前: 需要先将欲发送的数据结构序列化成 char 字节数组(buffer)。

  • 客户端调用 send(): 发送的其实是这个序列化后的字节数组。

  • 服务端调用 recv(): 接收到的是一个原始的字节数组。

  • 服务端处理数据前: 必须根据事先约定好的格式(如JSON),将这个字节数组反序列化,才能得到有意义的、可以操作的数据结构。

如果没有这个过程,收发双方根本无法理解彼此发送的原始字节到底代表什么


二,序列化和反序列化

现在开始我们将序列化和反序列化带到应用中来,接下来我会用比较简单的代码演示序列化和反序列化的流程用到的是C++jsoncpp


2-1 简单的序列化示例

Ubuntu 20.04 上,你可以通过包管理器轻松安装 jsoncpp

sudo apt install libjsoncpp-dev

简单的序列化示例

  • 创建 JSON 对象
Json::Value root;

  • 以键值对的形式,类似map一样存储数据
root["name"] = "Alice";
root["age"] = 25;
root["isStudent"] = false;

Json格式的序列化对象中,可以是键值对的格式,也可以是数组的格式,也可以是数组键值对混合的模式


  • 创建数组
Json::Value languages;
languages.append("C++");
languages.append("Python");
languages.append("JavaScript");
root["languages"] = languages;

  • 创建嵌套对象
Json::Value address;
address["city"] = "New York";
address["country"] = "USA";
root["address"] = address;

这里创建了一个keyaddress对应着一个键值对对象


  • 序列化为字符串并打印
Json::StyledWriter styledWriter;
std::string pretty_json = styledWriter.write(root); // 美化格式std::cout << "Serialized JSON:" << std::endl;
std::cout <<  pretty_json << std::endl;

完整代码

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>int main() {// 创建 JSON 对象Json::Value root;root["name"] = "Alice";root["age"] = 25;root["isStudent"] = false;// 创建数组Json::Value languages;languages.append("C++");languages.append("Python");languages.append("JavaScript");root["languages"] = languages;// 创建嵌套对象Json::Value address;address["city"] = "New York";address["country"] = "USA";root["address"] = address;// 序列化为字符串Json::StreamWriterBuilder writer;std::string json_str = Json::writeString(writer, root);std::cout << "Serialized JSON:" << std::endl;std::cout << json_str << std::endl;return 0;
}

演示结果

Serialized JSON:
{"address" : {"city" : "New York","country" : "USA"},"age" : 25,"isStudent" : false,"languages" : [ "C++", "Python", "JavaScript" ],"name" : "Alice"
}

2-1 简单的反序列化示例

  • 创建JSON 字符串
std::string json_str = R "({
"name": "Bob",
"age": 30,
"isStudent": true,
"languages": ["Java", "C#", "Go"],
"address": {"city": "San Francisco","country": "USA"
}
})
";

  • 解析 JSON
    Json::CharReaderBuilder reader;Json::Value root;std::string errors;std::istringstream json_stream(json_str);bool parsingSuccessful = Json::parseFromStream(reader, json_stream, &root, &errors);

Json::CharReaderBuilder reader;创建一个 CharReaderBuilder 对象,用于配置 JSON 解析器的行CharReaderBuilder 是一个工厂类,用于创建 CharReader 对象,它允许你定制化 JSON 解析的行为,默认情况下,它会创建一个遵循 JSON 标准的解析器,比如添加如下代码

Json::CharReaderBuilder reader;// 允许注释(JSON 标准不允许注释,但很多JSON文件包含注释)
reader.settings_["allowComments"] = true;// 允许尾随逗号(如 [1, 2, 3,])
reader.settings_["allowTrailingCommas"] = true;// 允许非引号键(如 {name: "John"},不符合JSON标准但常见)
reader.settings_["allowUnquotedKeys"] = false; // 默认false,保持严格// 允许单引号字符串(如 {'name': 'John'})
reader.settings_["allowSingleQuotes"] = false; // 默认false

Json::Value root;不过多讲解了,就是一个存放数据的对象

std::string errors;创建一个字符串变量,用于存储解析过程中可能出现的错误信息。这是一个输出参数,如果解析失败,这里会包含详细的错误信息,如果解析成功,这个字符串通常是空的,对于调试非常有用,可以告诉你是哪个字符位置出现了问题

std::istringstream json_stream(json_str),将 JSON 字符串包装成一个输入流std::istringstreamC++ 标准库中的字符串流类,它将字符串 json_str 转换为一个可以按顺序读取的流 Json::parseFromStream 需要一个流对象作为输入,而不是直接的字符串

使用流可以处理大型 JSON 数据(流式处理,不需要一次性加载到内存),更灵活,可以从文件、网络等多种源读取,符合 C++IO 流设计哲学


  • 提取数据

在学习提取数据之前,先学习一下Value的一些接口

类型检查接口

// 检查值的类型
bool isNull() const;      // 是否为 null
bool isBool() const;      // 是否为布尔值
bool isInt() const;       // 是否为 int
bool isUInt() const;      // 是否为 unsigned int
bool isIntegral() const;  // 是否为整数(包括有符号和无符号)
bool isDouble() const;    // 是否为 double
bool isNumeric() const;   // 是否为数字(整数或浮点数)
bool isString() const;    // 是否为字符串
bool isArray() const;     // 是否为数组
bool isObject() const;    // 是否为对象
bool isMember(const char* key) const; // 检查对象是否包含指定键

类型转换接口

bool asBool() const;          // 转换为 bool
int asInt() const;            // 转换为 int
unsigned int asUInt() const;  // 转换为 unsigned int
int64_t asInt64() const;      // 转换为 int64_t
uint64_t asUInt64() const;    // 转换为 uint64_t
double asDouble() const;      // 转换为 double
float asFloat() const;        // 转换为 float
const char* asCString() const;// 转换为 C 风格字符串
std::string asString() const; // 转换为 std::string

提取数据代码

    std::string name = root["name"].asString();int age = root["age"].asInt();bool isStudent = root["isStudent"].asBool();

其它的没有什么很难的了,直接展示完整代码

#include <jsoncpp/json/json.h>
#include <iostream>
#include <string>
using namespace std;
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
#include <sstream>int main() {// JSON 字符串std::string json_str = R"({"name": "Bob","age": 30,"isStudent": true,"languages": ["Java", "C#", "Go"],"address": {"city": "San Francisco","country": "USA"}})";// 解析 JSONJson::CharReaderBuilder reader;Json::Value root;std::string errors;std::istringstream json_stream(json_str);bool parsingSuccessful = Json::parseFromStream(reader, json_stream, &root, &errors);if (!parsingSuccessful) {std::cout << "Failed to parse JSON: " << errors << std::endl;return 1;}// 提取数据std::string name = root["name"].asString();int age = root["age"].asInt();bool isStudent = root["isStudent"].asBool();std::cout << "Name: " << name << std::endl;std::cout << "Age: " << age << std::endl;std::cout << "Is Student: " << (isStudent ? "Yes" : "No") << std::endl;// 处理数组std::cout << "Languages: ";const Json::Value languages = root["languages"];for (const auto& lang : languages) {std::cout << lang.asString() << " ";}std::cout << std::endl;// 处理嵌套对象std::string city = root["address"]["city"].asString();std::string country = root["address"]["country"].asString();std::cout << "Address: " << city << ", " << country << std::endl;return 0;
}

演示结果

root@hcss-ecs-f59a:/gch/code/HaoHao/learn3/day7# ./exe
Name: Bob
Age: 30
Is Student: Yes
Languages: Java C# Go 
Address: San Francisco, USA

文章转载自:

http://wdbAMSt2.skrxp.cn
http://wBg7kg0D.skrxp.cn
http://7aHeynci.skrxp.cn
http://hTir2cPP.skrxp.cn
http://5v660aJJ.skrxp.cn
http://dWipNYKf.skrxp.cn
http://svzm3AjH.skrxp.cn
http://tOSKFMNg.skrxp.cn
http://5NRiPCEd.skrxp.cn
http://5VrLX1cf.skrxp.cn
http://qOAe8YRq.skrxp.cn
http://m1CMChgD.skrxp.cn
http://2FHDPU6h.skrxp.cn
http://Fq0WiWXJ.skrxp.cn
http://kMvkTLFS.skrxp.cn
http://620Tv1nf.skrxp.cn
http://Ub6QDOy3.skrxp.cn
http://VzQfeWxs.skrxp.cn
http://VarEBT1r.skrxp.cn
http://Vl7udoN7.skrxp.cn
http://yQrynhrC.skrxp.cn
http://8g9Oy7rr.skrxp.cn
http://42ZJ2dsx.skrxp.cn
http://5szzdxA0.skrxp.cn
http://LznvJJGe.skrxp.cn
http://bU23OhIG.skrxp.cn
http://e3tYCh5v.skrxp.cn
http://fEbxAgqo.skrxp.cn
http://fUZRCFe4.skrxp.cn
http://2xXxX3A7.skrxp.cn
http://www.dtcms.com/a/385233.html

相关文章:

  • Java 代理模式-JDK动态代理
  • RabbitMQ 消息持久化与可靠性
  • 基于YOLO8的打架斗殴行为检测系统【源码+数据集+文章】
  • 电磁超声螺栓轴力检测技术:破解法兰泄露与设备安全痛点的关键方案
  • GPT-5深度解析:它真的是AGI的拂晓晨光吗?
  • (播放器开发)音频输出
  • 视频转音频在线工具大比拼,哪家体验更胜一筹?
  • 如何选择合适的工业绝缘监测仪
  • 【沉浸式解决问题】iPhone 6 登录苹果ID时一直跳出 unexpected error with certificate 或 无法登录
  • Linux系统的系统服务与DHCP服务
  • 高系分五:数据库系统
  • 高效精准的全基因组谱系贝叶斯推断方法SINGER
  • NetSuite Landed Cost到岸成本功能包
  • linux的停止自动休眠
  • 继承与组合:C++面向对象的核心
  • Java进阶教程,全面剖析Java多线程编程,多线程的实现方式,继承Thread类方式,笔记03
  • 猫头虎开源AI分享:一款CSV to Chat AI工具,上传CSV文件提问,它可以即时返回统计结果和可视化图表
  • Android中怎么使用C语言, 以及打包/使用SO动态库
  • 信刻光盘加密刻录系统,保护光盘分发数据安全保密!
  • 自由学习记录(99)
  • 【开题答辩全过程】以 C语言程序设计课程网站为例,包含答辩的问题和答案
  • RocketMQ 消息幂等性实战经验分享
  • [SC]SystemC中,一个namespace中调用了其他namespace中的函数,需要显示include那个函数所在的.h文件吗?
  • Origin气泡图画相关性系数图
  • 基于SpringBoot+Uniapp的儿童疫苗接种预约小程序(qq邮箱、二维码识别)
  • 基于HugeGraph构建法律知识图谱(一)
  • C语言常用字符串函数
  • 【STM32项目开源】STM32单片机智能饮水机控制系统
  • 新质生产力背景下基于“开源链动2+1模式+AI智能名片+S2B2C商城小程序”的商业机会挖掘研究
  • html隐藏文本利用原理,实现点击隐藏功能