Sylar C++高性能服务器学习记录21 【ByteArray模块-知识储备篇】

news2024/11/24 12:23:37

早在19年5月就在某站上看到sylar的视频了,一直认为这是一个非常不错的视频。
由于本人一直是自学编程,基础不扎实,也没有任何人的督促,没能坚持下去。
每每想起倍感惋惜,遂提笔再续前缘。

为了能更好的看懂sylar,本套笔记会分两步走,每个系统都会分为两篇博客。
分别是【知识储备篇】和【代码分析篇】
(ps:纯粹做笔记的形式给自己记录下,欢迎大家评论,不足之处请多多赐教)
QQ交流群:957100923


ByteArray模块-知识储备篇

一、我们写代码时没有思考的问题

我们在用编辑器或者高级点的IDE编写代码的时候,往往会忽略掉一些问题,潜意识当中认为这是“理所当然”的,比如以下的问题。

问:我们所写的代码(C++)是保存在哪里的?
答:保存在磁盘中,是一些文本文件。

问:我们使用编辑器编写C++代码时,你所编辑的操作会直接修改磁盘中的文件吗?
答:不会,因为编辑器是一个软件,或者说是一个程序,是运行在内存当中的。当我们用编辑器打开一个C++文件时,其实是这个编辑器程序调用文件IO将磁盘中对应C++文件的内容拷贝到了该编辑器程序所在的某段内存中。然后编辑器程序会将加载到的文件内容展现给我们看到。当我们编辑这个C++文件的时候,其实只是对这段内存中的数据进行修改,并不会改动对应磁盘中的文件。只有在特定情况下,编辑器才会触发对磁盘上的文件进行“写”的操作,比如我们按ctrl+s的时候。

问:写一个C++程序,他是怎么运行的呢?
答:这个步骤十分复杂,但是我们可以简单描述一下:首先我们已经知道代码源文件其实就是磁盘中的一些文本文件,那么如果要运行我们写的代码,就需要编译器来将我们写的文本文件编译成可执行文件(注意,这个可执行文件是提供给操作系统看的,可不是直接提供给CPU执行的),然后我们调用操作系统提供的接口或者命令来执行这个可执行文件(注意,可执行文件也是文件,也是存放在磁盘中的哦),此时操作系统就会将可执行文件加载到内存中,并且把可执行文件中的内容当做指令让CPU执行。

问:我们的程序归根结底是在干什么呢?
答:处理数据! 我们的代码分两个部分:第一部分是数据,第二部分是指令。在我们的程序中,数据就是存放在某个内存块中的具体的值,而指令就是对这个内存块的值进行读取或者修改的操作。

问:你可以解释一下 int a = 1; 这行代码吗?
答:首先我们写的代码是给编译器看的,比如C++代码需要通过C++编译器编译,所谓编译就是让编译器将源码文件翻译成可执行文件的过程(编译有很多阶段,我们不再深入)。那么站在编译器的角度我们先来分析这行代码:标记一块内存地址名称为a,这块地址的大小是int类型的大小,其中的内容为1。这里我们说的都是人话,实际上编译器会编译成可执行文件。接下来我们站在操作系统的角度来思考,操作系统会调用CPU来执行这行代码:首先选取一块空闲的内存,大小是4或8个字节(这里不深究是多少),将这块内存的内容设置为1。

问:如果你写了一个结构体,其中记录了一个用户对象的年龄和名称如下:

struct User{
	std::string name = "XYZ";
	int age = 29;
};

我们知道在程序运行时,这个结构体数据是在内存当中的,假如我们的程序遇到问题了需要停止运行,但是我们又不想丢失掉这部分数据,因为我们下次启动程序时还需要这份数据信息,我们有什么办法吗?
答:我们可以将数据信息存储到磁盘上,这样程序停止运行时虽然内存空间已经释放了,但是磁盘内容是持久化存储的,当我们再次运行程序的时候就可以从对应的磁盘中加载之前保存的那部分数据信息。

问:那我们该如何将数据保存到磁盘中呢?该以什么样的形式保存呢?
答:上述结构体User是写给编译器看的,其中真正的数据只有 “XYZ” 和 29。所以我们只要在磁盘上记录下这两个值就可以了。但是磁盘上存储的信息都是0和1,分不清具体表示什么,考虑到后续我们要从磁盘上读取,我们就需要知道从哪里开始多大的空间算作一个数据信息,那么我们就需要额外的一些信息来对这部分数据进行描述,以便能够后续准确的读取磁盘中的数据。

问:是否可以将以上所说的数据转换过程过程定义一个称呼呢?
答:我想将内存中的数据转化为方便磁盘存储的格式叫做 【序列化】,将磁盘数据加载到内存后转换为方便我们程序操作的格式过程叫做 【反序列化】。注意,这里的格式互相转换称之为【序列化】和【反序列化】,而不是存储到磁盘的过程,【序列化】与【反序列化】不仅仅方便磁盘存储,还可以用来网络通信等等。


二、序列化与反序列化

通过上面的问答,我想大家已经对序列化与反序列化有了一定的了解。那么如果是你,你会怎么做序列化的操作呢?
如果看过 【HOOK模块-知识储备篇】的第三点 编译器的限制(函数重载问题) 应该会有一些想法。我把部分内容搬过来看:

有以下一段代码:

int add(int x, int y){
	return x + y;
}

int main(int argc, char** argv){
	add(1,2);
}

C++编译器编译后使用 objdump 反汇编看看

g++ -o test test.cc
objdump -S test 

在这里插入图片描述
可以看到用C++编译器编译后将函数名称add 改成了 _Z3addii
_Z :表示linux环境下
3 :用接下来的三位表示函数名称
add :函数名称
ii :参数类型是 int int

这里划重点 【3 :用接下来的三位表示函数名称
哇🤩当时我看到这里时,觉得好(女少口我)!那我们是不是可以把这个方式用在序列化上呢?
假如我们要存储一个int类型的数据值为1,用二进制后我们不就可以这样表示了吗:

00000001 00000001

虽然两段数据一样,但是含义大不相同,第一个00000001意思是从这开始一个字节(8位)表示一个数据信息,也是就是接下来的 00000001 这8位表示一个整体,换算为十进制就是1。
为了避免大家搞混乱,我再举个例子,假如我要存储一个int类型的数据,值为3,我们该如何表示呢?

00000001 00000011

其中 00000001 表示接下来的1字节(8位)表示一个整体,这一个字节是 00000011 ,转为十进制就是 3。

当然有更详细的介绍,这里也只是抛转的作用,具体的可以看一下这一篇文章 【TLV编码通信协议设计】


三、TLV 格式结构

在上诉描述中我们使用的格式是LV格式,但这种格式只能描述最基本的类型,无法描述格式嵌套的结构,所以我们要改进他,增加一个类型标记T,使他更加的灵活。这也就诞生了TLV格式。

TLV:TLV是指由数据的类型Tag,数据的长度Length,数据的值Value组成的结构体,几乎可以描任意数据类型,TLV的Value也可以是一个TLV结构,正因为这种嵌套的特性,可以让我们用来包装协议的实现。
说白了用于描述基本数据的时候都能理解,但是TLV本身就是一种结构,所以为了灵活,也可以套娃的方式描述TLV结构。
在这里插入图片描述

1.Tag说明

Tag 描述Value的数据类型,TLV嵌套时可以用于描述消息的类型(说白了就是value是TLV数据也是支持的)
在这里插入图片描述

1.1.Tag首字节(注意红色箭头方向,别搞反了)

第6~7位:表示TLV的类型,00表示TLV描述的是基本数据类型(Primitive Frame, int,string,long…),01表示用户自定义类型(Private Frame,常用于描述协议中的消息)。

第5位: 表示Value的编码方式,分别支持Primitive及Constructed两种编码方式, Primitive指以原始数据类型进行编码,Constructed指以TLV方式进行编码,0表示以Primitive方式编码,1表示以Constructed方式编码。也就是说这里是否为1来标记是否 “套娃”

第0~4位: 当Tag Value小于0x1F(31)时也就是小于全是1的时候,首字节0~4位用来描述Tag Value,否则0~4位全部置1,作为存在后续字节的标志,Tag Value将采用后续字节进行描述。
在这里插入图片描述

1.2.Tag后续字节

后续字节采用每个字节的0~6位(即7bit)来存储Tag Value, 第7位用来标识是否还有后续字节。

第7位: 描述是否还有后续字节,1表示有后续字节,0表示没有后续字节,即结束字节。

第0~6位: 填充Tag Value的对应bit(从低位到高位开始填充),如:Tag Value为:0000001 11111111 11111111 (10进制:131071), 填充后实际字节内容为:10000111 11111111 01111111。
在这里插入图片描述

2. Length 描述Value的长度
2.1.定长方式(DefiniteForm)
定长方式中,按长度是否超过一个八位,又分为短、长两种形式,编码方式如下:

2.2.1.短形式

短形式: 字节第7位为0,表示Length使用1个字节即可满足Value类型长度的描述,范围在0~127之间的。

在这里插入图片描述
2.2.2.长形式

即Value类型的长度大于127时,Length需要多个字节来描述
这时第一个字节的第7位置为1
0~6位用来描述Length值占用的字节数,然后直将Length值转为byte后附在其后
如: Value大小占234个字节(11101010),由于大于127,这时Length需要使用两个字节来描述,10000001 11101010

在这里插入图片描述

2.2.不定长方式(IndefiniteForm)
Length所在八位组固定编码为0x80,但在Value编码结束后以两个0x00结尾。
这种方式使得可以在编码没有完全结束的情况下,可以先发送部分数据给对方。

在这里插入图片描述

3.Value 描述数据的值

由一个或多个值组成 ,值可以是一个原始数据类型(Primitive Data),也可以是一个TLV结构(Constructed Data)

3.1.原始数据类型(Primitive Data)

在这里插入图片描述

3.2.TLV结构(Constructed Data)

在这里插入图片描述

如果看完以上的内容还处于有点懵的状态,那么请多阅读几遍,也可以搜索下相关TLV的博客。
特别是 Tag 相关的解释,我想一定会有帮助。这将为接下来的代码分析打下基础。


四、总结

本篇博客其实还差一个demo,由于时间原因没有整理出来,若是关注博主的可以隔几天再来查看


【最后求关注、点赞、转发】
QQ交流群:957100923

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

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

相关文章

HTML静态网页成品作业(HTML+CSS)—— 金宝贝儿童教育机构介绍网页(2个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有2个页面。 二、作品演示 三、代…

社交创新:Facebook的技术与产品发展

在当今数字化时代,社交网络已经渗透到我们生活的方方面面,成为了人们日常交流、信息获取和社交互动的主要方式。而在这个众多社交平台中,Facebook作为其中的佼佼者,其技术与产品的发展历程也是一个社交创新的缩影。本文将探索Face…

从写简历到谈薪资的最全教程

从写简历到谈薪资的最全教程 目录简历注意事项举个例子写简历投递简历也有技巧模拟面试的重要性面试经验怎么刷不断迭代达越来越强斗智斗勇谈薪资拿到offer就结束了吗?我能给你的帮助 目录 大家好,我是一名普通本科毕业的学生,工作数年&#…

git根据历史某次提交创建新分支

有时候项目在做版本管理的时候,忘记了创建某次版本的分支,而直接在主分支上进行开发了,这个时候,想要对某次提交单独拉出来一个版本分支,就需要用到这个功能: git checkout -b 新分支名 某次提交的id 找到…

最新 Navicat Data Modeler 4 | 产品介绍

在过去的几周里,我们已经介绍了 Navicat 版本 17,现在我们来把注意力转移到另外两个值得关注的产品上,即 Navicat Data Modeler 和 Navicat BI(之前称为 Navicat Chart Creator)。今天的博客将介绍 Navicat Data Model…

VS2022+Qt雕刻机单片机马达串口上位机控制系统

程序示例精选 VS2022Qt雕刻机单片机马达串口上位机控制系统 如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助! 前言 这篇博客针对《VS2022Qt雕刻机单片机马达串口上位机控制系统》编写代码,代码整洁&a…

pypi 发布自己的包

注册pypi个人用户 网址:https://pypi.org 目录结构dingtalk_utils 必须-pkgs- __init__.py .gitignore LICENSE 必须 README.md 必须 requirements.txt setup.py 必须安装依赖 pip install setuptools wheel安装上传工具 pip install twinesetup.py i…

深度学习(三)

5.Functional API 搭建神经网络模型 5.1利用Functional API编写宽深神经网络模型进行手写数字识别 import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom sklearn.datasets import load_irisfrom sklearn.model_selection import train_test_splitfrom…

蒋耀锴:剑桥毕业,硅谷敲代码8年,回国创业做低代码

这是《开发者说》的第10期,本期我们邀请的开发者是蒋耀锴,曾在意大利、英国、美国读书,专长高性能计算、高容错分布式系统与软件工程,毕业后在硅谷的Medallia写了8年代码,19年回国创业做低代码,喜欢半夜里一…

常见Rabbitmq面试题及答案总结

1、 什么是 rabbitmq 釆用AMQP高级消息队列协议的一种消息队列技术撮大的特点就是消费并不需要 确保提供方存在,实现了服务之间的高度解耦 2、 为什么要使rabbitmq (1) 在分布式系统下具备异步,削峰,负载均衡等一系列高级功能&…

汽车MCU虚拟化--对中断虚拟化的思考(2)

目录 1.引入 2.TC4xx如何实现中断虚拟化 3.小结 1.引入 其实不管内核怎么变,针对中断虚拟化无非就是上面两种,要么透传给VM,要么由Hypervisor统一分发。汽车MCU虚拟化--对中断虚拟化的思考(1)-CSDN博客 那么,作为车规MCU龙头…

手把手制作Vue3+Flask全栈项目 全栈开发之路实战篇 问卷网站(五)数据处理

全栈开发一条龙——前端篇 第一篇:框架确定、ide设置与项目创建 第二篇:介绍项目文件意义、组件结构与导入以及setup的引入。 第三篇:setup语法,设置响应式数据。 第四篇:数据绑定、计算属性和watch监视 第五篇 : 组件…

Java学习中,如何理解注解的概念及常用注解的使用方法

一、简介 Java注解(Annotation)是一种元数据,提供了一种将数据与程序元素(类、方法、字段等)关联的方法。注解本身不改变程序的执行逻辑,但可以通过工具或框架进行处理,从而影响编译、运行时的…

Suryxin’s ACM退役记

序 我的记忆力很差,经历过的很多事情都已经记不太清了,其中有很多美好回忆也已经消散,我很惋惜没能留存一些照片和声音或是文字供我怀念,这就像《泰坦尼克号》一样,露丝和杰克感人肺腑的爱情故事,最后也仅…

东航携手抖音生活服务开启机票首播,推出国内、国际超值机票次卡

在民航暑运旺季到来之际,越来越多的用户选择提前做好旅行规划,囤下高性价比的出游商品。6月6日18点,中国东方航空(以下简称“东航”)将在抖音开启首次机票直播,推荐多款超值机票次卡及空中Wi-Fi等特色产品&…

SpringBoot发邮件服务如何配置?怎么使用?

SpringBoot发邮件需要的参数?邮件发送性能如何优化? 在SpringBoot项目中配置发邮件服务是一个常见的需求,它允许我们通过应用程序发送通知、验证邮件或其他类型的邮件。AokSend将详细介绍如何在SpringBoot中配置发邮件服务。 SpringBoot发邮…

nginx和proxy_protocol协议

目录 1. 引言2. HTTP server的配置3. Stream server的配置3.1 作为proxy_protocol的前端服务器3.2 作为proxy_protocol的后端服务器1. 引言 proxy_protocol 是haproxy开发的一种用于在代理服务器和后端服务器之间传递客户端连接信息的协议。使用 proxy_protocol 的主要优势是能…

QT获取最小化,最大化,关闭窗口事件

QT获取最小化,最大化,关闭窗口事件 主程序头文件: 实现: changeEvent,状态改变事件 closeEvent触发点击窗口关闭按钮事件 其代码它参考: /*重写该函数*/ void MainWindow::changeEvent(QEvent *event) {…

蚓链数字化营销生态的影响力分享!

​家人们,今天来给大家分享一些关于数字化平台生态化对数字营销影响的具体案例。 比如某电商平台,通过生态化的建设,实现了精准的推荐算法。根据用户的浏览历史和购买行为,为他们推荐最符合需求的商品,大大提高了购买…

JeeSite 快速开发平台 Vue3 前端版介绍

JeeSite 快速开发平台 Vue3 前端版介绍: 它构建于 Vue3、Vite、Ant-Design-Vue、TypeScript 以及 Vue Vben Admin 等最前沿的技术栈之上,能助力初学者迅速上手并顺利融入团队开发进程。涵盖的模块包括组织机构、角色用户、菜单授权、数据权限、系统参数…