计算机网络基础(3)_应用层自定义协议与序列化

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

计算机网络基础(3)_应用层自定义协议与序列化

收录于专栏【计算机网络】
本专栏旨在分享学习计算机网络的一点学习笔记,欢迎大家在评论区交流讨论💌 

目录

1. 应用层 

再谈协议 :

网络版计算器 :  

2. 序列化和反序列化

3. 重新理解 read, write, recv, send 和 tcp 为什么支持全双工

4. 流式数据处理

5. Jsoncpp

特性 :

安装

6. Json实现序列化和反序列化

序列化 : 

反序列化 :

总结 : 

7. Json::Value  

构造函数 : 

访问元素

类型检查

赋值和类型转换

数组和对象操作 


1. 应用层 

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

再谈协议 :

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

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

网络版计算器 :  

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

约定方案一 : 

客户端发送一个形如 "1 + 1" 的字符串

这个字符串中有两个操作数, 都是整形

两个数字之间会有一个字符是运算符, 运算符只能是 "+"

数字和运算符之间没有空格

.......

定义方案二 :  

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

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

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

2. 序列化和反序列化

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

如果我们采用方案二, 我们也要体现协议定制的细节

我们要引用序列化和反序列化, 只不过我们直接采用了现成的方案 --- jsoncpp 库

我们要对 socket 进行字节流的读取处理

3. 重新理解 read, write, recv, send 和 tcp 为什么支持全双工

所以 : 

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

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

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

4. 流式数据处理

你如何保证你每次读取就能读完请求缓冲区的所有内容?

你怎么保证读取完毕或者读取没有完毕的时候, 读到的就是一个完整的请求呢?

处理 TCP 缓冲区中的数据, 一定要保证正确处理请求

const std::string ProtSep = " ";
const std::string LineBreakSep = "\n";
// "len\nx op y\n" : \n 不属于报文的一部分,约定std::string Encode(const std::string &message)
{std::string len = std::to_string(message.size());std::string package = len + LineBreakSep + message +LineBreakSep;return package;
}
// "len\nx op y\n" : \n 不属于报文的一部分,约定// 我无法保证 package 就是一个独立的完整的报文
// "l
// "len
// "len\n
// "len\nx
// "len\nx op
// "len\nx op y
// "len\nx op y\n"
// "len\nx op y\n""len
// "len\nx op y\n""len\n
// "len\nx op
// "len\nx op y\n""len\nx op y\n"
// "len\nresult code\n""len\nresult code\n"
bool Decode(std::string &package, std::string *message)
{// 除了解包,我还想判断报文的完整性, 能否正确处理具有"边界"的报文auto pos = package.find(LineBreakSep);if (pos == std::string::npos)return false;std::string lens = package.substr(0, pos);int messagelen = std::stoi(lens);int total = lens.size() + messagelen + 2 * LineBreakSep.size();if (package.size() < total)return false;// 至少 package 内部一定有一个完整的报文了!*message = package.substr(pos + LineBreakSep.size(),messagelen);package.erase(0, total);return true;
}

 所以完整的处理过程为 :

5. Jsoncpp

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

特性 :

1. 简单易用 : Jsoncpp 提供了直观的 API, 使得处理 JSON 数据变得简单.

2. 高性能 : Jsoncpp 的性能经过优化, 能够高效地处理大量 JSON 数据.

3. 全面支持 : 支持 JSON 标准中的所有数据类型, 包括对象, 数组, 字符串, 数字, 布尔值和 null

4. 错误处理 : 在解析 JSON 数据时, Jsoncpp 提供了详细的错误信息和位置, 方便开发者调试

安装

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

6. Json实现序列化和反序列化

序列化 : 

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

1. 使用 Json:Value 的 toStyledString 方法 :

优点 : 将 Json::Value 对象直接转换为格式化的 JSON 字符串

实例 : 

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

2. 使用 Json::StreamWriter : (推荐)

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

示例 :

#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>int main()
{Json::Value root;root["name"] = "joe";root["sex"] = "男";Json::StreamWriterBuilder swb;// StreamWriter 的工厂std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());std::stringstream ss;sw->write(root, &ss);std::cout << ss.str() << std::endl;return 0;
}

3. 使用 Json::FastWrite : 

优点 : 比 StyleWriter 更快, 因为它不添加额外的空格和换行符

示例 :  

#include <iostream>
#include <string>
#include <sstream>
#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;
}

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

反序列化 :

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

1. 使用Json::Reader :

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

示例 :

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
int main()
{// JSON 字符串std::string json_string = "{\"name\":\"张三\",\"age\":30, \"city\":\"北京\"}";// 解析 JSON 字符串Json::Reader reader;Json::Value root;// 从字符串中读取 JSON 数据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;
}

2. 使用 Json::CharReader 的派生类 (不推荐, 上面的足够了) 

在某些情况下, 你可能需要更精细地控制解析过程, 可以直接使用 Json::CharReader 的派生类.

但通常情况下, 使用 Json::parseFromStream 或 Json::Reader 的 parse 方法足够了. 

总结 : 

1. toStyledString, StreamWrite 和 FastWrite 提供了不同的序列化选项, 你可以根据具体需求选择使用.

2. Json::Reader 和parseFromStream 函数是 Jsoncpp 中主要的反序列化工具, 它们提供了强大的错误处理机制

3. 在进行序列化和反序列化时, 请确保处理所有可能的错误情况, 并验证输入和输出的有效性

7. Json::Value  

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

构造函数 : 

• Json::Value():默认构造函数,创建一个空的 Json::Value 对象。

Json::Value(ValueType type, bool allocated = false):根据给定的ValueType(如 nullValue, intValue, stringValue 等)创建一个Json::Value对象

访问元素

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类型的键。 

类型检查

• bool isNull():检查值是否为 null。

• bool isBool():检查值是否为布尔类型。

• bool isInt():检查值是否为整数类型。

• bool isInt64():检查值是否为 64 位整数类型。

• bool isUInt():检查值是否为无符号整数类型。

• bool isUInt64():检查值是否为 64 位无符号整数类型。

• bool isIntegral():检查值是否为整数或可转换为整数的浮点数。

• bool isDouble():检查值是否为双精度浮点数。

• bool isNumeric():检查值是否为数字(整数或浮点数)。

• bool isString():检查值是否为字符串。

• bool isArray():检查值是否为数组。

• bool isObject():检查值是否为对象(即键值对的集合)。

赋值和类型转换

Json::Value& operator=(bool value):将布尔值赋给Json::Value 对象。

Json::Value& operator=(int value):将整数赋给 Json::Value 对象。

Json::Value& operator=(unsigned int value):将无符号整数赋给Json::Value 对象。

Json::Value& operator=(Int64 value):将 64 位整数赋给Json::Value对象。

Json::Value& operator=(UInt64 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():将值转换为整数类型(如果可能)。

Int64 asInt64():将值转换为 64 位整数类型(如果可能)。

unsigned int asUInt():将值转换为无符号整数类型(如果可能)。

UInt64 asUInt64():将值转换为 64 位无符号整数类型(如果可能)。

double asDouble():将值转换为双精度浮点数类型(如果可能)。

std::string asString():将值转换为字符串类型(如果可能)

数组和对象操作 

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.xdnf.cn/news/14142.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

前言 --- 《跟着小王学Python》

前言 《跟着小王学Python》 是一套精心设计的Python学习教程&#xff0c;适合各个层次的学习者。本教程从基础语法入手&#xff0c;逐步深入到高级应用&#xff0c;以实例驱动的方式&#xff0c;帮助学习者逐步掌握Python的核心概念。通过开发游戏、构建Web应用、编写网络爬虫、…

【C#设计模式(8)——过滤器模式(Adapter Pattern)】

前言 滤液器模式可以很方便地实现对一个列表中的元素进行过滤的功能&#xff0c;能方便地修改滤器的现实&#xff0c;符合开闭原则。 代码 //过滤接口public interface IFilter{List<RefuseSorting> Filter(List<RefuseSorting> refuseList);}//垃圾分类public cla…

开源共建 | 长安链开发常见问题及规避

长安链开源社区鼓励社区成员参与社区共建&#xff0c;参与形式包括不限于代码贡献、文章撰写、社区答疑等。腾讯云区块链王燕飞在参与长安链测试工作过程中&#xff0c;深入细致地总结了长安链实际开发应用中的常见问题及其有效的规避方法&#xff0c;相关内容多次解答社区成员…

什么是RAG? LangChain的RAG实践!

1. 什么是RAG RAG的概念最先在2020年由Facebook的研究人员在论文《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》中提出来。在这篇论文中他们提出了两种记忆类型&#xff1a; 基于预训练模型&#xff08;当时LLM的概念不像现在这么如日中天&#xff0…

第二十一章、Qt对XML文件进行读写操作详解

目录 一、XML文件的简介 二、QXML的接口介绍 三、XML示例 四、QXML的介绍 5.1、QDomDocument详解 5.2、QDomElement详解 5.3、QDomAttr详解 六、使用QXML解析XML示例 七、构建并保存xml 一、XML文件的简介 可扩展标记语言 (Extensible Markup Language, XML) ,标准通…

03-axios常用的请求方法、axios错误处理

欢迎来到“雪碧聊技术”CSDN博客&#xff01; 在这里&#xff0c;您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者&#xff0c;还是具有一定经验的开发者&#xff0c;相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导&#xff0c;我将…

小小的mfc100u.dll文件到底是什么?mfc100u.dll丢失的解决方法有哪些?

对于许多电脑用户来说&#xff0c;软件突然无法启动并显示“mfc100u.dll丢失”是一件非常头疼的事情。你可能正急于完成一份重要的文档&#xff0c;或者沉浸在紧张刺激的游戏关卡中&#xff0c;而这个错误提示就像一盆冷水&#xff0c;无情地浇灭了你的热情。这个小小的mfc100u…

华为eNSP:MSTP

一、什么是MSTP&#xff1f; 1、MSTP是IEEE 802.1S中定义的生成树协议&#xff0c;MSTP兼容STP和RSTP&#xff0c;既可以快速收敛&#xff0c;也提供了数据转发的多个冗余路径&#xff0c;在数据转发过程中实现VLAN数据的负载均衡。 2、MSTP可以将一个或多个VLAN映射到一个Inst…

使用cloudflare搭建私人docker镜像站

背景 大家是否也有docker镜像拉取速度慢&#xff0c;甚至直接拉不下来的情况&#xff0c;我们可以使用cloudflare加速拉取镜像。 申请域名 开始前需要准备cloudflare账号并自购一个域名。域名可以在云厂商购买&#xff0c;可以看到非主流域名比较实惠。 购买完成后在域名控…

晶振选择指南:应对温度波动的关键因素

晶振的选择对于电子设备来说至关重要&#xff0c;尤其是在面对温度波动的情况下。晶振作为时钟信号源&#xff0c;其性能直接影响到设备的稳定性和可靠性。因此&#xff0c;在选择晶振时&#xff0c;需要根据实际应用场景以及对时钟精度的要求来进行。以下是一些建议&#xff1…

gpu-V100显卡相关知识

一、定义 RuntimeError: FlashAttention only supports Ampere GPUs or newer.torch attention注意力接口学习V100 架构是什么&#xff1f; 二、实现 RuntimeError: FlashAttention only supports Ampere GPUs or newer. 报错原因分析&#xff1a; GPU机器配置低&#xff0c;…

【go从零单排】HTTP客户端和服务端

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在 Go 语言中&#xff0c;net/http 包提供了强大的 HTTP 客户端和服务器功能。 &…

从Web2到Web3:区块链推动的数字进化之路

互联网的演变从最初的Web1到如今的Web3&#xff0c;代表了技术和用户需求的深刻变化。Web3是一个基于区块链技术的全新互联网架构&#xff0c;旨在解决传统互联网&#xff08;即Web2&#xff09;中数据集中化和隐私保护等问题。通过去中心化的机制&#xff0c;Web3不仅能够增强…

vue自定义计算器组件

自定义组件实现以下简单的计算器功能&#xff1a; 创建计算器组件文件calculator.vue&#xff0c;代码如下&#xff1a; <template><div class"calculator"><!-- 当前运算过程显示区域 --><div class"expression">{{ currentExpr…

希音面试:亿级用户 日活 月活,如何统计?(史上最强 HyperLogLog 解读)

本文原文链接 尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 如何 统计一个 网站 的日活、月活数&a…

2023年MathorCup数学建模B题城市轨道交通列车时刻表优化问题解题全过程文档加程序

2023年第十三届MathorCup高校数学建模挑战赛 B题 城市轨道交通列车时刻表优化问题 原题再现&#xff1a; 列车时刻表优化问题是轨道交通领域行车组织方式的经典问题之一。列车时刻表规定了列车在每个车站的到达和出发&#xff08;或通过&#xff09;时刻&#xff0c;其在实际…

Python数据分析NumPy和pandas(三十一、数据聚合)

聚合是指从数组生成标量值的数据转换。上一次学习的代码示例使用了其中几个聚合函数&#xff0c;包括 mean、count、min 和 sum。常见的聚合见下图列表&#xff0c;但是&#xff0c;不仅限于列表中的这组方法。在 GroupBy 对象上调用聚合函数&#xff08;例如&#xff1a; mean…

公链数字钱包开发与加密钱包App原生开发

随着区块链技术的不断发展&#xff0c;数字货币和去中心化金融&#xff08;DeFi&#xff09;的兴起&#xff0c;公链数字钱包的需求日益增加。数字钱包不仅为用户提供存储、管理和交易数字资产的工具&#xff0c;而且也为区块链技术的应用提供了一个重要的入口。开发一个安全、…

0. 0:《跟着小王学Python·新手》

《跟着小王学Python新手》系列 《跟着小王学Python》 是一套精心设计的Python学习教程&#xff0c;适合各个层次的学习者。本教程从基础语法入手&#xff0c;逐步深入到高级应用&#xff0c;以实例驱动的方式&#xff0c;帮助学习者逐步掌握Python的核心概念。通过开发游戏、构…

HTTPTomcatServle之HTTP详解

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…