news 2026/4/15 19:46:20

TCP:协议、序列化与反序列化、JSON 数据和jsoncpp

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TCP:协议、序列化与反序列化、JSON 数据和jsoncpp

协议

概念:

Linux 网络的语境下,协议指的是一套标准化的规则和约定,它规定了网络中不同的计算机、设备或程序之间如何进行可靠、高效的数据通信。简单来说,协议就是设备之间通信的“共同语言”和“行为准则”。没有协议,网络设备就像说着不同语言、没有交通规则的人在街上乱走,无法有效沟通。

其实,协议就是双方约定好的结构化的数据

序列化与反序列化

在Linux网络编程中,序列化反序列化是将数据转换为适合网络传输的格式(和反向转换)的关键过程。下面详细解释这两个概念及其在Linux网络中的应用:

什么是序列化与反序列化

• 定义结构体来表示我们需要交互的信息;

• 发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按照相同的规则把字符串转化回结构体;

• 这个过程叫做"序列化" 和"反序列化"

序列化(Serialization)

将数据结构或对象状态转换为字节流的过程,以便:

  • 网络传输
  • 持久化存储
  • 进程间通信

反序列化(Deserialization)

将字节流还原为原始数据结构或对象的过程。

为什么需要序列化

  1. 方便网络发送
  2. 方便协议的可扩展性和可维护性
// 示例:直接发送结构体会有问题structPerson{charname[50];intage;floatsalary;};// 问题:// 1. 内存对齐差异// 2. 字节序差异(大端/小端)// 3. 结构体填充差异// 4. 指针无效(指向的地址在接收端无意义)

下面这幅图详细展示了序列化与反序列化

一幅图理解tcp 为什么支持全双工

• 在任何一台主机上,TCP 连接既有发送缓冲区,又有接受缓冲区,所以,在内核中,可以在发消息的同时,也可以收消息,即全双工

• 这就是为什么一个tcp sockfd 读写都是它的原因

• 实际数据什么时候发,发多少,出错了怎么办,由TCP 控制,所以TCP 叫做传输控制协议

由此,我们可以得到几个结论

  1. TCP网络发送数据本质是把数据从发送缓冲区通过网络拷贝到对端的接受缓冲区
  2. TCP支持全双工本质是有一对接受和发送缓冲区
  3. 我们认为在每一个发送单元都是一个cp问题,是用户和内核之间进行生产和消费
  4. 发送和接收数据时数据有没有发完整、收完整,TCP并不关心,而是由用户自己控制维护(如数据包粘包问题)

什么是粘包问题?

粘包(Packet Sticking/Concatenation)是指在网络通信中,接收方一次性接收到的数据包含了多个独立的应用层消息,或者一个完整的消息被拆分到多个数据包中接收的现象。

根本原因

TCP协议的特性(主要原因):
○ TCP是面向字节流的协议,没有消息边界概念
○ 数据在传输层被分割成TCP段,在接收端重新组装
○ 发送方多次write()的数据可能被合并成一个TCP段发送
○ 接收方一次read()可能读取到多个应用层消息
内核缓冲区机制:
○ 发送/接收缓冲区可能导致数据积累和合并

UDP vs TCP

  • UDP:不会出现粘包,因为UDP是面向数据报的,每个sendto()对应一个独立的数据报
  • TCP:必然需要考虑粘包问题,是流式协议的特性决定的

总结:粘包不是TCP的缺陷,而是其流式特性的必然结果。解决粘包问题的核心在于设计明确的应用层消息格式,确保接收方能正确识别每个独立的消息边界。

JSON 数据

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它使用人类可读的文本来表示结构化数据。JSON 已成为现代 Web 应用和 API 中最常用的数据格式之一。

基本特点

  1. 轻量级:相比 XML 更简洁,占用空间小
  2. 易读性:文本格式,人类可直接阅读和理解
  3. 语言独立:几乎所有编程语言都支持 JSON
  4. 自描述性:数据结构清晰,容易理解

JSON 的六种数据类型

字符串(String)

"这是一个字符串""name":"张三""email":"zhangsan@example.com"

数字(Number)

42// 整数3.14// 浮点数-10// 负数2.5e4// 科学计数法(25000)

布尔值(Boolean)

truefalse

空值(Null)

null

对象(Object)

{"name":"张三","age":25,"isStudent":true,"address":{"city":"北京","street":"中关村"}}

数组(Array)

["苹果","香蕉","橙子"][1,2,3,4,5][{"id":1},{"id":2},{"id":3}]

JSON 语法规则

  1. 键值对结构:“键”:值
  2. 逗号分隔:键值对之间用逗号分隔
  3. 花括号包裹对象:{ }
  4. 方括号包裹数组:[ ]
  5. 键必须是字符串:必须用双引号包裹
  6. 值可以是任意类型:字符串、数字、对象、数组等

JSON 的局限性

  1. 不支持注释:JSON 规范不支持注释
  2. 二进制数据:不适合存储二进制数据(需要使用 Base64 编码)
  3. 日期格式:没有内置的日期类型(通常用 ISO 8601 字符串表示)
  4. 文件大小:对于非常大的数据,可能不如二进制格式高效

jsoncpp

Jsoncpp 是一个用于处理JSON 数据的C++ 库。它提供了将JSON 数据序列化为字符串以及从字符串反序列化为C++ 数据结构的功能。Jsoncpp 是开源的,广泛用于各种需要处理JSON 数据的C++ 项目中

主要特点

跨平台支持

  • 支持 Windows、Linux、macOS 等主流操作系统
  • 与多种编译器兼容(GCC、Clang、MSVC 等)

核心功能

  • JSON 解析:将 JSON 字符串或文件解析为 C++ 数据结构
  • JSON 序列化:将 C++ 数据结构转换为 JSON 字符串
  • JSON 操作:增删改查 JSON 数据
  • JSON 验证:验证 JSON 数据的有效性

主要组件

Json::Value

  • JSON 值的容器,可表示对象、数组、字符串、数字等
  • 支持类似字典的访问方式

Json::Reader(旧版) /Json::CharReader(新版)

  • 用于解析 JSON 字符串

Json::Writer(旧版) /Json::StreamWriter(新版)

  • 用于将 Json::Value 序列化为字符串

使用

序列化

序列化指的是将数据结构或对象转换为一种格式,以便在网络上传输或存储到文件中。Jsoncpp 提供了多种方式进行序列化:toStyledString、StreamWriter 和FastWriter,这里只介绍StreamWriter(这个最常用也是最佳实践)

使用Json::StreamWriter:

○优点:提供了更多的定制选项,如缩进、换行符等。

○示例:

#include<iostream>#include<string>#include<sstream>#include<memory>#include<jsoncpp/json/json.h>usingnamespacestd;intmain(){Json::Value root;root["name"]="joe";root["sex"]="男";Json::StreamWriterBuilder wbuilder;// StreamWriter 的工厂wbuilder["emitUTF8"]=true;// 输出会保留 UTF-8 字符的原生形式unique_ptr<Json::StreamWriter>writer(wbuilder.newStreamWriter());stringstream ss;writer->write(root,&ss);cout<<ss.str()<<endl;return0;}

反序列化

反序列化指的是将序列化后的数据重新转换为原来的数据结构或对象。Jsoncpp 提供了以下方法进行反序列化:Json::Reader和Json::CharReader 的派生类,这里只介绍Json::Reader

** 使用Json::Reader:**

○优点:提供详细的错误信息和位置,方便调试。

○示例:

#include<iostream>#include<string>#include<jsoncpp/json/json.h>usingnamespacestd;intmain(){// JSON 字符串//在字符串中,如果你想包含一个双引号,但双引号又是字符串的边界符,这时就需要转义。string json_string="{\"name\":\"张三\",\"age\":30, \"city\":\"北京\"}";// 解析JSON 字符串Json::Reader reader;Json::Value root;// 从字符串中读取JSON 数据boolparsingSuccessful=reader.parse(json_string,root);if(!parsingSuccessful){// 解析失败,输出错误信息cout<<"Failed to parse JSON: "<<reader.getFormattedErrorMessages()<<endl;return1;}// 访问JSON 数据string name=root["name"].asString();intage=root["age"].asInt();string city=root["city"].asString();// 输出结果cout<<"Name: "<<name<<endl;cout<<"Age: "<<age<<endl;cout<<"City: "<<city<<endl;return0;}

优点

  1. 简单易用:API 设计直观
  2. 纯 C++:不依赖其他语言或运行时
  3. 性能良好:满足大多数应用场景需求
  4. 活跃维护:持续更新和维护
  5. 头部文件单一:#include <jsoncpp/json/json.h>

缺点

  1. 错误处理:错误信息有时不够详细
  2. 性能:对于超大型 JSON 文件,性能可能不如专门的解析器
  3. 内存使用:解析时会一次性加载整个 JSON 到内存

适用场景

  • 配置文件读取/写入
  • API 数据交换
  • 数据持久化
  • 与 Web 服务通信
  • 日志记录

安装

ubuntu:sudo apt-get install libjsoncpp-dev Centos:sudo yum install jsoncpp-devel
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/14 11:53:12

HuggingFace Model Hub搜索技巧快速定位目标模型

HuggingFace Model Hub搜索技巧快速定位目标模型 在如今的AI开发中&#xff0c;没人愿意把时间浪费在“为什么这个模型跑不起来”上。你可能已经经历过这样的场景&#xff1a;从HuggingFace Model Hub下载了一个看起来很理想的预训练模型&#xff0c;满怀期待地运行代码&#…

作者头像 李华
网站建设 2026/4/11 19:21:54

Java小白面试之旅:从Spring Boot到微服务架构

场景&#xff1a;互联网大厂Java小白求职者面试 在一个阳光明媚的早晨&#xff0c;超好吃走进了互联网大厂的面试室&#xff0c;面对他的是一位严肃但和蔼的面试官。 第一轮提问&#xff1a;基础技术与框架 面试官&#xff1a;请你介绍一下Java SE 8的一些新特性&#xff0c;以…

作者头像 李华
网站建设 2026/4/11 11:03:43

解决单元测试中的依赖注入问题

在单元测试中,模拟依赖关系并进行依赖注入是常见但有时令人头疼的问题。本文将通过一个具体的例子,详细探讨如何解决在单元测试中遇到的一个常见问题:当使用依赖注入框架(如Microsoft.Extensions.DependencyInjection)时,如何正确地设置模拟对象。 问题背景 假设我们有…

作者头像 李华
网站建设 2026/4/12 21:27:54

Next.js与Edamam API的协奏曲:解决API请求问题

在使用Next.js开发一个食谱搜索应用时,我们可能会遇到一些API请求的问题。这篇博客将详细介绍如何解决在调用Edamam API时出现的ERR_BAD_REQUEST错误,通过一个具体的实例来展示问题的解决过程。 背景介绍 我们使用Axios库来发起对Edamam API的请求,目的是获取根据用户输入…

作者头像 李华
网站建设 2026/4/7 13:24:02

【Cursor AI编辑器】AI原生IDE的技术革命

文章目录目录一、核心技术架构&#xff1a;三层深度集成二、自研Composer模型&#xff1a;性能与智能的完美平衡三、2.0革命性功能&#xff1a;多智能体与全链路开发1. 多智能体并行架构(Multi-Agents)2. Agent模式&#xff1a;从"以文件为中心"到"以目标为中心…

作者头像 李华