前置知识
在深入本文之前,建议熟悉序列化与反序列化的基本概念。对于基于 TCP 协议通信的双方,由于 TCP 是面向字节流的,发送数据前通常需要定义结构化的数据容器。直接传递内存字节会引发字节序和内存对齐问题,因此需要借助序列化将结构化数据转换为连续的字节流。
JSON 基础与使用
JSON(JavaScript Object Notation)是一种轻量级、基于文本的数据交换格式。它源于 JavaScript,但已广泛应用于多种编程语言。JSON 本质上是符合特定规范的字符串,支持对象、数组、字符串、数字、布尔值和 null 等类型。
在实际开发中,我们通常使用成熟的第三方库来处理 JSON。C++ 中常用的 json.hpp(即 nlohmann/json)提供了丰富的接口。它通过一个类对象映射并承载解析后的 JSON 数据,大大简化了处理流程。
初始化与操作
json 类的定义位于 nlohmann 命名空间内。创建对象主要有两种方式:
- 列表初始化:利用 C++11 特性,直接传递键值对或元素。
#include "json.hpp"
using json = nlohmann::json;
int main() {
// 对象初始化
json j = {{"name", "WZ"}, {"age", 20}};
// 数组初始化
json arr = {1, 2, 3};
return 0;
}
- 赋值运算符:更符合 C++ 标准库容器的使用习惯。
json j;
j["name"] = "wz";
j["age"] = 20;
序列化与反序列化
dump() 成员函数用于序列化,返回 std::string。不传参数时生成紧凑格式;传入整数参数则进行格式化缩进。网络传输中通常建议使用紧凑格式以减少体积。
反序列化使用静态成员函数 parse()。为了处理转义字符繁琐的问题,C++11 引入了原始字符串字面量 R"()" 语法,方便构造 JSON 字符串。
std::string s = R"({"name":"WZ","age":18})";
json j = json::parse(s);
原理剖析
json.hpp 内部维护一个 json 类,包含类型变量与联合体形式的值变量。联合体设计使得同一时刻只能表示一种数据类型。构造函数根据输入决定类型标签,并在堆上分配相应的存储空间(如 或 )。 重载实现了灵活的访问逻辑,若当前为空对象,会自动转为对应类型并初始化。


