【Linux网络】应用层自定义协议与序列化

应用层自定义协议与序列化

应用层

我们程序员写的一个个解决我们实际问题,满足我们日常需求的网络程序,都是在应用层.

协议是一种"约定".Socket的接口,在读写数据时,都是按"字符串"的方式来发送接收的.如果我们要传输一些"结构化的数据"怎么办呢?

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

网络版计算器

例如,我们需要实现一个服务器版的加法器.我们需要客户端把要计算的两个加数发过去, 然后由服务器进行计算,最后再把结果返回给客户端.

约定方案一:

  • 客户端发送一个形如"1+1"的字符串;
  • 这个字符串中有两个操作数,都是整形;
  • 两个数字之间会有一个字符是运算符,运算符只能是+;
  • 数字和运算符之间没有空格;

约定方案二:

  • 定义结构体来表示我们需要交互的信息;
  • 发送数据时将这个结构体按照一个规则转换成字符串,接收到数据的时候再按照相同的规则把字符串转化回结构体;
  • 这个过程叫做"序列化"和"反序列化"

序列化和反序列化

在这里插入图片描述

无论我们采用方案一,还是方案二,还是其他的方案,只要保证,一端发送时构造的数据,在另一端能够正确的进行解析,就是ok的.这种约定,就是应用层协议

但是,为了让我们深刻理解协议,打算自定义实现一下协议的过程。

  • 我们采用方案2,我们也要体现协议定制的细节
  • 我们要引入序列化和反序列化,只不过我们课堂直接采用现成的方案–jsoncpp库
  • 我们要对socket进行字节流的读取处理

理解read、write、recv、send和tcp支持全双工

在这里插入图片描述

所以:

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

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

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

Json

Jsoncpp

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

特性

  1. 简单易用:Jsoncpp提供了直观的API,使得处理JSON数据变得简单。
  2. 高性能:Jsoncpp的性能经过优化,能够高效地处理大量JSON数据。
  3. 全面支持:支持JSON标准中的所有数据类型,包括对象、数组、字符串、数字、布尔值和null。
  4. 错误处理:在解析JSON数据时,Jsoncpp提供了详细的错误信息和位置,方便开发者调试。
    当使用Jsoncpp库进行JSON的序列化和反序列化时,确实存在不同的做法和工具类可供选择。以下是对Jsoncpp中序列化和反序列化操作的详细介绍:

安装

C++

  • ubuntu: sudo apt - get install libjsoncpp - dev
  • Centos: sudo yum install jsoncpp - devel

序列化

序列化指的是将数据结构或对象转换为一种格式,以便在网络上传输或存储到文件中。Jsoncpp提供了多种方式进行序列化:

  1. 使用Json::Value的toStyledString方法
    • 优点:将Json::Value对象直接转换为格式化的JSON字符串。
    • 示例
#include <iostream>
#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;
}

执行结果:

{"name" : "joe","sex" : "男"
}
  1. 使用Json::StreamWriter
    • 优点:提供了更多的定制选项,如缩进、换行符等。
    • 示例
#include <iostream>
#include <string>
#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;
}

执行结果:

{"name" : "joe","sex" : "男"
}
  1. 使用Json::FastWriter
    • 优点:比StyledWriter更快,因为它不添加额外的空格和换行符。
    • 示例
#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;
}

执行结果:

{"name":"joe","sex":"男"}

另一种写法示例:

#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>int main()
{Json::Value root;root["name"] = "joe";root["sex"] = "男";Json::StyledWriter writer;std::string s = writer.write(root);std::cout << s << std::endl;return 0;
}

执行结果:

{"name" : "joe","sex" : "男"
}

反序列化

反序列化指的是将序列化后的数据重新转换为原来的数据结构或对象。Jsoncpp提供了以下方法进行反序列化:

  1. 使用Json::Reader
    • 优点:提供详细的错误信息和位置,方便调试。
    • 示例
#include <iostream>
#include <jsoncpp/json/json.h>int main() {std::string json_string = "{\"name\":\"张三\",\"age\":30,\"city\":\"北京\"}";// 解析JSON字符串Json::Value root;Json::Reader reader;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;
}

执行结果:

Name: 张三
Age: 30
City: 北京
  1. 使用Json::CharReader的派生类(不推荐,上面的足够了)
    在某些情况下,你可能需要更精细地控制解析过程,可以直接使用Json::CharReader的派生类。
    但通常情况下,使用Json::parseFromString或Json::Reader的parse方法就足够了。

总结

你可以用toStyledString、StreamWriter和FastWriter提供了不同的序列化选项,它们提供强大的错误处理机制。
Json::Reader和parseFromString函数是Jsoncpp中主要的反序列化工具,在进行序列化和反序列化时,请确保处理所有可能的错误情况,并验证输入和输出的有效性。

Json::Value

Json::Value是Jsoncpp库中的一个重要类,用于表示和操作JSON数据结构。以下是一些常用的Json::Value操作列表:

  1. 构造函数
    • Json::Value():默认构造函数,创建一个空的Json::Value对象。
    • Json::Value(Json::ValueType type, bool aValue = false):根据给定的类型创建一个Json::Value对象。
  2. 访问元素
    • Json::Value& operator[](const char key)*:通过键(字符串)访问对象中的元素。如果键不存在,则创建一个新的元素。
    • Json::Value& operator[](const std::string& key):同上,但使用std::string类型的键。
    • Json::Value& operator[](ArrayIndex index):通过索引访问数组中的元素。如果索引超出范围,则创建一个新的元素。
    • Json::Value at(const char key)*:通过键访问对象中的元素,如果键不存在则抛出异常。
    • Json::Value at(const std::string& key):同上,但使用std::string类型的键。
  3. 类型检查
    • bool isNull():检查值是否为null类型。
    • bool isBool():检查值是否为布尔类型。
    • bool isInt():检查值是否为32位整数类型。
    • bool isInt64():检查值是否为64位整数类型。
    • bool isUInt():检查值是否为无符号整数类型。
    • bool isUInt64():检查值是否为64位无符号整数类型。
    • bool isIntegral():检查值是否为整数或可转换为整数的浮点数。
    • bool isDouble():检查值是否为双精度浮点数。
    • bool isNumeric():检查值是否为数字(整数或浮点数)。
    • bool isString():检查值是否为字符串。
    • bool isArray():检查值是否为数组。
    • bool isObject():检查值是否为对象(即键值对的集合)。
  4. 赋值和类型转换
    • Json::Value& operator=(bool value):将布尔值赋给Json::Value对象。
    • Json::Value& operator=(int value):将32位整数赋给Json::Value对象。
    • Json::Value& operator=(int64_t value):将64位整数赋给Json::Value对象。
    • Json::Value& operator=(uint value):将无符号整数赋给Json::Value对象。
    • Json::Value& operator=(uint64_t value):将64位无符号整数赋给Json::Value对象。
    • Json::Value& operator=(double value):将双精度浮点数赋给Json::Value对象。
    • Json::Value& operator=(const char value)*:将C字符串赋给Json::Value对象。
    • Json::Value& operator=(const std::string& value):将std::string赋给Json::Value对象。
    • bool asBool():将值转换为布尔类型(如果可能)。
    • int asInt():将值转换为32位整数类型(如果可能)。
    • Int64 asInt64():将值转换为64位整数类型(如果可能)。
    • UInt64 asUInt64():将值转换为64位无符号整数类型(如果可能)。
    • std::string asString():将值转换为字符串类型(如果可能)。
  5. 数组和对象操作
    • size_t size():返回数组或对象中的元素数量。
    • bool empty():检查数组或对象是否为空。
    • void resize(ArrayIndex newSize):调整数组的大小。
    • void clear():删除数组或对象中的所有元素。
    • void append(const Json::Value& value):在数组末尾添加一个新元素。
    • Json::Value& operator[](const char key, const Json::Value& defaultValue = Json::nullValue)*:在对象中插入或访问一个元素,如果键不存在则使用默认值。
    • Json::Value& operator[](const std::string& key, const Json::Value& defaultValue = Json::nullValue):在对象中插入或访问一个元素,如果键不存在则使用默认值,但使用std::string类型的键。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/82408.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/82408.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL + Elasticsearch:为什么要使用ES,使用场景与架构设计详解

MySQL Elasticsearch&#xff1a;为什么要使用ES&#xff0c;使用场景与架构设计详解 前言一、MySQL Elasticsearch的背景与需求1.1 为什么要使用Elasticsearch&#xff08;ES&#xff09;&#xff1f;1.2 为什么MySQL在某些场景下不足以满足需求&#xff1f;1.3 MySQL Elas…

PPL困惑度的计算

1. 公式 PPL&#xff08;Perplexity&#xff09;困惑度 是自然语言处理&#xff08;NLP&#xff09;中常用的评估语言模型&#xff08;Language Model&#xff09;性能的指标。PPL 用于衡量语言模型对语言序列的预测能力&#xff0c;数值越小&#xff0c;说明模型的预测能力越…

MegaCLI Raid管理工具

整理在CentOS 7.9和Ubuntu 24.04上&#xff0c;MegaCLI 工具的安装与常用命令。 1. 参考 下载和安装MegaCLI工具 MegaCli RAID管理工具 Megacli 批量磁盘巡检 ubuntu24.04 No such file libncursesw.so.5 dell服务器硬盘的状态变成外来&#xff08;foreign&#xff09;命…

HTML9:页面结构分析

页面结构分析 元素名描述header标题头部区域的内容&#xff08;用于页面或页面中的一块区域&#xff09;footer标记脚部区域的内容&#xff08;用于整个页面或页面的一块区域&#xff09;sectionWeb页面的一块独立区域article独立的文章内容aside相关的内容或应用&#xff08;…

分布式处理架构

分布式处理架构是一种将计算任务分散到多台计算机或服务器上协同完成的系统设计方法。这种架构通过将工作负载分配到多个节点&#xff08;可以是物理机、虚拟机或容器&#xff09;来提高性能、可靠性和可扩展性。下面我将从多个角度详细解释这一概念&#xff1a; 分布式架构的…

算法每日一题 | 入门-分支结构-Apples Prologue/苹果和虫子

Apples Prologue/苹果和虫子 题目描述 小 B 喜欢吃苹果。她现在有 m m m&#xff08;1 ≤ m ≤100&#xff09;个苹果&#xff0c;吃完一个苹果需要花费 t t t&#xff08;0 ≤ t≤ 100&#xff09;分钟&#xff0c;吃完一个后立刻开始吃下一个。 现在时间过去了 s s s&a…

RT Thread Studio创建软件和硬件RTC工程

MCU型号&#xff1a;STM32F103RET6 一.配置软件模拟RTC 1.生成一个带串口输出的工程文件&#xff0c;新建RT-Thread项目工程文件。 2.查看电路图中的串口输出管脚&#xff0c;根据STMCubeMx软件可知此串口为USART1&#xff0c;选择芯片型号为STM32F103RET6&#xff0c;控制台…

STC32G12K128-旋转编码器-软件去抖

STC32G12K128-旋转编码器-软件去抖 简介代码 简介 EC11旋转编码器是一种可以连续旋转的器件A,B,C为旋转编码引脚&#xff0c;带按键的有D,E引脚。引脚功能&#xff1a; A&#xff1a;编码器A相&#xff1b;B&#xff1a;编码器B相&#xff1b;C&#xff1a;公共端-一般接到GN…

配置Jupyter Notebook环境及Token认证(Linux服务器)

配置Jupyter Notebook环境及Token认证&#xff08;Linux服务器&#xff09; 背景 在Ubuntu 18.04.6 LTS服务器&#xff08;IP: 39.105.167.2&#xff09;上&#xff0c;基于虚拟环境pytorch_env&#xff0c;通过Mac终端&#xff08;SSH&#xff09;配置Jupyter Notebook环境&…

从零开始学Flink:开启实时计算的魔法之旅

在凌晨三点的数据监控大屏前&#xff0c;某电商平台的技术负责人突然发现一个异常波动&#xff1a;支付成功率骤降15%。传统的数据仓库此时还在沉睡&#xff0c;而基于Flink搭建的实时风控系统早已捕捉到这个信号&#xff0c;自动触发预警机制。当运维团队赶到时&#xff0c;系…

基于k8s的Jenkins CI/CD平台部署实践(三):集成ArgoCD实现持续部署

基于k8s的Jenkins CI/CD平台部署实践&#xff08;三&#xff09;&#xff1a;集成ArgoCD实现持续部署 文章目录 基于k8s的Jenkins CI/CD平台部署实践&#xff08;三&#xff09;&#xff1a;集成ArgoCD实现持续部署一、Argocd简介二、安装Helm三、Helm安装ArgoCD实战1. 添加Arg…

[C++类和对象]类和对象的引入

面向过程和面向对象 C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用来逐步解决问题 C是基于面向对象的,关注的是对象,将一件事情分成不同的对象,靠对象之间完成交互 类的引入 C语言结构体中只能定义变量,在C中,结构体不仅仅可以定义变量,而且可以定义函…

AWS之存储服务

目录 一、传统存储术语 二、传统存储与云存储的关系 三、云存储之AWS 使用场景 文件存储 数据块存储 对象存储 EBS、EFS、S3对比 EBS块存储 S3对象存储 S3 使用案例 S3 存储类 EFS文件存储 一、传统存储术语 分类 接口/技术类型 应用场景特点 关系及区别 机械硬…

WPDRRC 模型:构建动态闭环的信息安全防御体系

WPDRRC 模型是一种信息安全整体架构设计模型&#xff0c;由预警&#xff08;Warning&#xff09;、保护&#xff08;Protection&#xff09;、检测&#xff08;Detection&#xff09;、反应&#xff08;Reaction&#xff09;、恢复&#xff08;Recovery&#xff09;和反击&…

Redis 数据类型详解(二):Hash 类型全解析

文章目录 一、什么是 Redis 的 Hash 类型&#xff1f;二、Hash为什么在有些时候比String好用三、常见命令1.HSET key field value2.HGET key field3.HMSET4.HMGET5.HGETALL6.HKEYS7.HVALS8.HINCRBY9.HSETNX 四、应用场景五、性能优势六、注意事项总结 提示&#xff1a;以下是本…

Go Modules 的基本使用

在 Go Modules 项目中&#xff0c;首次运行时下载依赖包的正确流程需要根据项目情况区分处理。以下是详细步骤和最佳实践&#xff1a; 一、首次初始化项目的标准流程 1.1 创建项目目录并初始化模块 mkdir myproject && cd myproject go mod init github…

RISC-V AIA SPEC学习(五)

第六章 Interrupts for Virtual Machines(VS Level) 核心内容 1.VS级别外部中断支持:​​ ​​客户中断文件(Guest Interrupt File)​​:虚拟机的每个vCPU拥有独立的IMSIC中断文件,允许直接接收设备MSI。​​vstopi CSR​​:类似stopei,用于虚拟机内部处理最高优先级中…

【Python-Day 11】列表入门:Python 中最灵活的数据容器 (创建、索引、切片)

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…

【AXI总线专题】-AXI-LITE总线解读

【AXI总线专题】-AXI-LITE总线解读 1.axi-lite概述2.信号定义Write address channelWrite data channelWrite response channelRead address channelRead data channel 3.测试4.仿真波形5.工程文件 参考手册 《3-2-03米联客2022版AXI4总线专题-20211123.pdf》 《IHI0022E_amba_…

在企业级项目中高效使用 Maven-mvnd

1、引言 1.1 什么是 Maven-mvnd? Maven-mvnd 是 Apache Maven 的一个实验性扩展工具(也称为 mvnd),基于守护进程(daemon)模型构建,目标是显著提升 Maven 构建的速度和效率。它由 Red Hat 推出,通过复用 JVM 进程来减少每次构建时的启动开销。 1.2 为什么企业在构建过…