【网络编程】网络传输-JSON

发布于:2025-07-21 ⋅ 阅读:(15) ⋅ 点赞:(0)

一、JSON概述

JSON(JavaScript Object Notation)是一种轻量级、基于文本的数据交换格式,旨在简洁地表示结构化数据,同时兼顾人类可读性和机器解析效率。它起源于 JavaScript 的对象语法,但目前已成为独立于编程语言的通用数据格式,被广泛用于前后端通信、服务间数据交换、配置文件等场景。
在这里插入图片描述

JSON格式主要有以下的特点:

  1. 相比 XML 等格式,JSON 语法简洁(无冗余标签),数据体积更小,传输和解析效率更高。
  2. 基于 Unicode 字符,可直接被人类阅读和编写,便于调试和手动修改。
  3. 几乎所有编程语言(C++、Java、Python、JavaScript 等)都有成熟的 JSON 解析 / 生成库,无需额外适配
  4. 数据结构本身包含字段名,无需额外 schema 即可理解数据含义

二、JSON的语法规则

JSON的语法比较简单,主要是由一个个键值对和有序列表组成,语法规则如下:

2.1 基本结构

  • 对象(Object):表示键值对的集合,用 {} 包裹,键值对之间用逗号 , 分隔。

    • 键(key)必须是字符串,且用双引号 " 包裹(不能用单引号)。
    • 值(value)可以是字符串、数字、布尔值、null、对象或数组。
  • 数组(Array):表示有序的值列表,用 [] 包裹,元素之间用逗号 , 分隔,元素类型可以是任意 JSON 数据类型(包括对象、数组)。

2.2 数据类型

  • 字符串:必须用双引号 " 包裹,支持转义字符(如 \" 表示双引号、\n 表示换行),例如 "name": "Alice"
  • 数字:整数(如 42)、浮点数(如 3.14)、负数(如 -10),不支持八进制 / 十六进制(需用十进制表示)。
  • 布尔值truefalse(小写)。
  • null:表示空值(小写 null)。
  • 对象(Object):嵌套的键值对集合,例如 {"user": {"id": 1, "name": "Bob"}}
  • 数组(Array):有序元素列表,例如 {"hobbies": ["reading", "coding"]}

注意事项

  • 键必须是字符串(双引号包裹),不能是数字或其他类型。
  • 元素之间用逗号分隔,但最后一个元素后不能有逗号(否则会解析错误)。
  • 区分大小写(true 正确,True 错误)。
  • 不支持注释(标准 JSON 语法中无注释,部分扩展格式如 JSON5 支持,但非通用)

2.3 JSON数据结构示例

2.3.1 简单JSON结构

{
  "name": "张三",
  "age": 25,
  "isStudent": false,
  "height": 1.75,
  "address": null
}

2.3.2 嵌套JSON结构

{
  "user": {
    "id": 1001,
    "info": {
      "name": "李四",
      "contact": {
        "phone": "123456789",
        "email": "lisi@example.com"
      }
    }
  }
}

2.3.3 数组(有序列表)

{
  "fruits": ["apple", "banana", "orange"],
  "scores": [90, 85.5, 95],
  "isPass": [true, false, true]
}

2.3.4 复杂JSON结构(数组+嵌套)

{
  "class": "高三(1)班",
  "students": [
    {
      "name": "王五",
      "age": 18,
      "subjects": ["数学", "英语"]
    },
    {
      "name": "赵六",
      "age": 17,
      "subjects": ["物理", "化学"]
    }
  ]
}

三、JSON的使用场景

  1. 数据交换

    • 前后端通信:浏览器与服务器之间的 HTTP 请求 / 响应(如 AJAX、RESTful API),几乎是标准格式。
    • 服务间通信:微服务架构中,不同服务(如 Java 后端与 C++ 服务)通过 JSON 交换数据,避免语言差异导致的兼容性问题。
  2. 配置文件

    • 相比 XML 更轻量,比 INI 更灵活(支持嵌套结构),例如:
{
  "server": {
    "port": 8080,
    "timeout": 30,
    "log": {
      "level": "info",
      "path": "/var/log/server.log"
    }
  }
}
  1. 数据存储
    部分 NoSQL 数据库(如 MongoDB)直接使用 JSON-like 格式(BSON)存储数据,便于灵活扩展字段。

四、序列化和反序列化JSON

序列化和反序列化JSON有许多成熟的处理库,比如使用C++编程语言可以使用nlohmann/json库,这是一个轻量级的JSON库,风格偏向现代C++,并且只有一个.hpp文件,不需要额外链接库

4.1 下载nlohmann-json

Ubuntu下,可以使用包管理器下载,下载完成后自动安装到系统路径/usr/include

sudo apt update
sudo apt install nlohmann-json3-dev

Windows可以在github上下载源码,手动安装:https://github.com/nlohmann/json/releases

4.2 序列化JSON

我们下面介绍一个例子,用于序列化嵌套的JSON,可以发现,这个库的语法风格十分像STL,对STL熟悉的话就可以自己琢磨出用法,详细手册查看:https://json.nlohmann.me/

  • 可以使用[]来添加对应key-value值,这里会发送自动的类型转换,key一般是std::string类型
  • 或者使用at()函数,这个是返回一个引用,因此可以修改对应的值,并且它具有边界检查
  • 嵌套JSON就是将key设置为JSON类型
  • 初始化JSON类型支持初始化列表的模式
void serializeJson(LoginMsg const& msg,json* pJson){
    (*pJson)["user"] = msg.user;
    (*pJson)["password"] = msg.pwd;
    
    //嵌套Json
    json jDate = {{"year",msg.date.year},{"month",msg.date.month},{"day",msg.date.day}};
    (*pJson)["date"] = jDate;

    json jTime = {{"hour",msg.time.hour},{"minute",msg.time.min},{"second",msg.time.sec}};
    (*pJson)["time"]= jTime;

    std::cout << "===== serialize json =====" << std::endl;    
    std::cout << pJson->dump(4) << std::endl;
}

序列化好的JSON数据结构可以使用dump成员函数来打印,其中dump(4)表示设置4位的缩进值

{
    "date": {
        "day": 20,
        "month": 7,
        "year": 2025
    },
    "password": "xx123456789",
    "time": {
        "hour": 14,
        "minute": 30,
        "second": 15
    },
    "user": "Antonio"
}

4.3 反序列化JSON

  • 反序列化JSON可以从json类中像STLmap一样通过[]at()访问,与上述序列化一致
  • 不论是[]还是at(),都是返回一个json的引用,因此支持链式调用,用起来很方便
void deserializeJson(json* pJson){
    std::cout << "===== deserialize json =====" << std::endl;

    std::string user = pJson->at("user");
    std::string password = pJson->at("password");
    
    Date date;
    date.year = pJson->at("date").at("year");
    date.month = pJson->at("date").at("month");
    date.day = pJson->at("date").at("day");
    
    Time time;
    time.hour = pJson->at("time").at("hour");
    time.min = pJson->at("time").at("minute");
    time.sec = pJson->at("time").at("second");

    std::cout << "user = " << user << std::endl;
    std::cout << "password = " << password << std::endl;
    std::cout << "date = [" << " year = " << date.year << " month = " << date.month << " day = " << date.day <<" ]" << std::endl;;
    std::cout << "time = [" << " hour = " << time.hour << " minute = " << time.min << " second = " << time.sec << " ]" << std::endl; 
}

4.4 测试结果

完整的测试代码如下

#include<iostream>
#include<nlohmann/json.hpp>

using json = nlohmann::json;

struct Date{
    int year;
    int month;
    int day;
};

struct Time{
    int hour;
    int min;
    int sec;
};

struct LoginMsg{
    std::string user;
    std::string pwd;
    
    Date date;
    Time time;

};

void serializeJson(LoginMsg const& msg,json* pJson){
    (*pJson)["user"] = msg.user;
    (*pJson)["password"] = msg.pwd;
    
    //嵌套Json
    json jDate = {{"year",msg.date.year},{"month",msg.date.month},{"day",msg.date.day}};
    (*pJson)["date"] = jDate;

    json jTime = {{"hour",msg.time.hour},{"minute",msg.time.min},{"second",msg.time.sec}};
    (*pJson)["time"]= jTime;

    std::cout << "===== serialize json =====" << std::endl;    
    std::cout << pJson->dump(4) << std::endl;
}

void deserializeJson(json* pJson){
    std::cout << "===== deserialize json =====" << std::endl;

    std::string user = pJson->at("user");
    std::string password = pJson->at("password");
    
    Date date;
    date.year = pJson->at("date").at("year");
    date.month = pJson->at("date").at("month");
    date.day = pJson->at("date").at("day");
    
    Time time;
    time.hour = pJson->at("time").at("hour");
    time.min = pJson->at("time").at("minute");
    time.sec = pJson->at("time").at("second");

    std::cout << "user = " << user << std::endl;
    std::cout << "password = " << password << std::endl;
    std::cout << "date = [" << " year = " << date.year << " month = " << date.month << " day = " << date.day <<" ]" << std::endl;;
    std::cout << "time = [" << " hour = " << time.hour << " minute = " << time.min << " second = " << time.sec << " ]" << std::endl; 
}

int main(){
    std::string user = "Antonio";
    std::string password = "xx123456789";

    Date date = {2025,7,20};
    Time time = {14,30,15};

    LoginMsg loginMsg = {user,password,date,time};

    json* pJLoginMsg = new json();
    serializeJson(loginMsg,pJLoginMsg);
    
    deserializeJson(pJLoginMsg);

    delete pJLoginMsg;

    return 0;
}

序列化JSON和反序列化JSON的测试输出结果如下:

在这里插入图片描述

更多资料:https://github.com/0voice


网站公告

今日签到

点亮在社区的每一天
去签到