- 博客(80)
- 收藏
- 关注
原创 C++个人复习(4)
组件定义用途主要特性获取异步操作结果的对象获取异步操作的结果阻塞等待结果,检查结果状态设置异步操作结果的对象在线程中设置值,另一个线程获取设置值或异常,创建与future关联的对象可调用对象,封装任务与future关联封装任务并异步执行,获取结果封装任意可调用对象,调用后可以获取结果std::async异步执行函数的标准库函数简单启动异步任务并获取结果自动管理线程,支持执行策略:用于在不同线程间传递结果。它可以从异步操作中获取返回值。:用于设置一个值或者异常,这些值或异常会被对应的。
2024-11-21 18:44:59
1125
原创 网络基础(4)IP协议
对于这个报文的第二行还没有进行说明。下面就来说明首先我们知道网络是分5层的(下图没有画硬件层):TCP可以向底层发送多个报文,由此网络层也就可以包装出多个报文,但是在数据链路层存在一个规定:至于原因在讲解数据链路层的时候进行说明。一般来说上层交下来一个报文就会封装一个数据帧。这个不能太大,到底是多大呢?在Linux中可以通过ifconfig指令查看,其中有一个字段叫做mtu这个eth0就是其中一个网络接口的名字。未来网络收发数据都是通过这个eth0来进行收发。
2024-11-19 16:33:59
1164
原创 网络协议(4)拥塞控制
之前已经说过了tcp也是会考虑网络的情况的,也就是当网络出现问题的时候tcp不会再对报文进行重传。当所有的用户在网络不好的时候都不会对丢失的报文进行重传。这样就会防止网络瘫痪。这样的机制也就是tcp会进行拥塞控制。
2024-11-18 15:12:23
1275
原创 个人C++复习(3)
通俗点讲就是数据在内存中的存放顺序。大端序:高字节存储在内存的低地址处,低字节存储在高地址处。例如,对于16进制数0x12345678,大端序在内存中的存储方式是:12 34 56 78。小端序:低字节存储在内存的低地址处,高字节存储在高地址处。对于同样的16进制数0x12345678,小端序在内存中的存储方式是:78 56 34 12。通过使用消息队列和工作线程的设计,可以有效地将所有操作调度到一个线程中执行,从而避免了多线程带来的复杂性和潜在问题。
2024-11-17 15:18:11
1437
原创 个人C++复习知识点(2)
适用于需要手动管理线程生命周期的传统多线程编程。jthread提供了更高层次的抽象,简化了线程管理,并引入了中断机制,使得编写和管理线程的代码更加安全和简洁。while (!// 请求中断return 0;需要注意的是虽然jthread提供了一些改善中断的接口,但是在标准库中没有真正的中断功能。适用于需要存储和传递多种可调用对象的场合。std::bind适用于需要固定某些参数或调整参数顺序的情况。Lambda 表达式适用于需要简洁、局部的可调用对象,并且可以方便地捕获外部变量的场合。
2024-11-17 13:57:29
943
原创 网络基础(3)https和加密
首先数据摘要等于数据指纹也就是两者是同一个东西。只不过摘要更加技术化一点,指纹更加形象一点。数字指纹(数据摘要),其基本原理是利⽤单向散列函数(Hash函数)对信息进⾏运算,⽣成⼀串固定⻓度的数字摘要(就是将你的数据经过哈希函数生成一串新的数据)。数据指纹并不是⼀种加密机制,但可以⽤来判断数据有没有被篡改。那么为什么数据指纹不算加密呢?因为这种方式并没有什么方法进行解密。也就是如果一个数据进行哈希了是没有什么方法还原的。既然不是用来加密的,这是用来干什么的呢?
2024-11-15 08:52:18
1567
原创 个人C++复习知识点(1)
在 C++ 中,函数参数的顺序可以作为重载的条件之一。通过不同的参数顺序,可以定义多个同名函数,从而提高代码的灵活性和可读性。然而,在使用函数重载时,需要注意参数类型、数量和顺序的组合,以避免二义性和潜在的错误。
2024-11-14 15:11:55
1246
原创 网络基础(2)http协议
以上是http协议的第一个知识点。通过上面的URL能够知道在URL中是存在很多的特殊字符的。在上面百度的获取资源的URL中可以看到是将bit通过get方法给了wd然后再将wd拼接到URL中的。那么如果我将URL中的特殊字符写到wd中会发生什么呢。可以看到wd中的内容就被编码成为了上图中的样子。所以在百度这里如果你的搜索中存在一些URL中的特殊字符,那么就会对这些特殊字符进行转化,转化成为上图中国的%3A%2B%2F%23%3F这个编码也就是urlencode和urldecode:
2024-11-14 12:51:20
401
原创 网络基础(2)简单socket包装,序列化与反序列
在去写代码之前,我们再去学习一些知识:首先在客户端和服务端建立联系之后,双方是处于平等的地位的,并不是只能由服务端向客户端发送信息,客户端也是可以向服务端发送信息的。双方是可以互发消息的,原因就是TCP是具有接收和发送缓冲区的。客户端和服务端都是具有发送和接收缓冲区的。我们先来看客户端,对于客户端而言是需要在用户态定义一个buff(这个buff形态各异,在之前的代码就是我们定义的一个一个的string/char bufff),也就是用户级缓冲区。
2024-11-13 20:22:29
973
原创 仿RabitMQ 模拟实现消息队列项目开发文档4(个人项目)
从这个项目能够知道的就是这个消息队列能够解决的就是忙先不均,起到负载均衡作用,并且是在各个不同的主机上,而不再是在一个主机上。首先明确我们所实现的项目:仿RabbitMQ实现一个简化版的消息队列组件,其内部实现了消息队列服务器以及客户端的搭建,并支持不同主机间消息的发布与订阅及消息推送功能(这里还应该有客户端的按需获取功能,也就是消费者客户端能够根据自己的需求从服务器上拉取消息过来)。
2024-11-12 14:17:35
1032
原创 仿RabitMQ 模拟实现消息队列项目开发文档3(个人项目)
由此就提出了信道的概念,这个信道就是单独的一个为用户提供服务的通道,而不同的信道也是具有不同的功能的,加入某一个信道提供的功能为订阅了一个队列的消息,那么这个信道对应的客户端就是消费者,而如果另外一个信道提供的服务为发布一个消息,那么这个信道对应的客户端就是生产者,由此就产生了不同的两种角色,生产者和消费者。在消费者的管理模块那里就已经提到过信道的概念了,信道就是对连接的再次分解,让一个连接区分出不同的信道,然后不同的信道各自为一个客户端提供独特的服务,例如有的信道提供的服务就是分发一条消息。
2024-11-12 14:02:10
694
原创 仿RabitMQ 模拟实现消息队列项目开发文档2(个人项目)
项目需求分析核心概念现在需要将这个项目梳理清楚了,便于之后的代码实现。项目中具有一个生产消费模型:其中生产者和消费者的个数是可以灵活改变的,让系统资源更加合理的分配。消息队列的主逻辑和上面的逻辑基本一样,只不过我现在要做的这个生产者不再是本地的一个线程了,而是一个客户端,消费者也是一个客户端,生产者就是消息发布客户端,而消费者就是消息订阅客户端,而中间的就不是线程安全的阻塞队列了,而是一个消息队列服务器:消息队列服务器能够存储消息,消息发布客户端能够将消息发送到客户端上,而消
2024-11-11 15:37:07
1092
原创 仿RabitMQ 模拟实现消息队列项目开发文档1(个人项目)
ProtoBuf(全称Protocol Buffer)是数据结构序列化和反序列化框架,它具有以下特点: • 语⾔⽆关、平台⽆关:即 ProtoBuf ⽀持 Java、C++、Python 等多种语⾔,⽀持多个平台 • ⾼效:即⽐ XML 更⼩、更快、更为简单 • 扩展性、兼容性好:你可以更新数据结构,⽽不影响和破坏原有的旧程序,这个库是由谷歌完成的一个库,最后不破坏原有的旧程序可以理解为,这个库和原有的旧程序互相之间的独立性是比较高的。
2024-11-10 16:00:07
728
原创 负载均衡式在线oj项目开发文档2(个人项目)
下面就是思考这个表中具有哪些属性列了,首先题目的编号肯定是要具有的(number,类型int,long都是可以的),下一个属性列就是题目的标题(tittle,字符串)了,标题之后就是这个题目的难度了,下一个题目的难度(star字符串),下一个就是题目的描述,题目的描述一般都是长文本(text类型),然后就是预设给用户的代码,自然使用的也是长文本(text),然后是测试用例,依旧是长文本(text),之后就是题目的时间限制(int)和题目的空间限制了(int)已上面的属性列来进行表的创建。
2024-11-09 15:14:31
1222
原创 网络基础(1)网络编程套接字TCP,守护进程化
通过上面的代码我们已经知道了客户端和服务端能够使用read和write从网络中获取信息。IO类的函数,write/read在底层已经做了转网络序列的工作下一个信息和UDP和TCP协议的特点有关。首先UDP是用于数据报的,而TCP则是面向字节流的。那么这个用于数据报和面向字节流有什么不同呢?到目前为止,这两个东西在编码上的区别是很小的,但是从底层上来说这两个协议的实现是具有很大的不同的。
2024-04-30 20:35:37
1126
1
原创 网络基础(1)网络编程套接字UDP
要完成网络编程首先要理解原IP和目的IP,这在上一节已经说明了。也就是一台主机要进行通信必须要具有原IP和目的IP地址。
2024-04-30 20:14:18
1792
原创 网络基础(1)
我们都知道计算机是只认识0和1的,但是不同的机器对于这种0和1信息的识别也是不一样的,例如有的设备对于0和1信息的识别靠的是电流的频率,而有的设备对于0和1信息的识别靠的是电流的强弱,也就是每种品牌的电脑,内部是被0和1信息都是被供应商做好规定了的。磁盘的供应商有自己的协议,网卡有自己的协议。两个人在打电话,逻辑上两个人是直接在通电话,但是物理上我的声音是被我的电话接收,然后我的电话经过种种的处理,然后将处理过的信息传递给对面的电话机,对面的电话机在对接收的信息进行处理,才让两个人实现了电话的通信。
2024-04-06 15:03:04
1201
原创 简单线程池的实现
这样写有几个好处,当有好几个线程检测到这里的_instance为nullptr时,会都进入到第一个if中,然后在这里获取锁,而只有一个线程能够得到锁,然后去到第二个if中创建单例对象,之后这个线程会释放锁,其它线程获取到锁之后,此时_instance已经不是nullptr了自然就不会继续创建单例对象了。对于这个下限和上限的具体的数量,是根据业务情况而定的,这里就可以写一个配置文件,在配置文件中写明低水位线为多少,高水位线为多少,然后在构造函数中读取这个文件,将低水位线和高水位线的值获取到即可。
2024-03-29 15:04:00
798
原创 线程的互斥,生产消费者模型
在之前的学习种我们知道了在,多线程的情况下,对一个全局变量做++,并不是原子的。并且在之前的学习中,我们学习到了给临界区加锁,在之前的代码中我们使用的是一个全局的锁。并且为了保证锁能够保护临界区,所以这里首先就要保证申请锁是一个安全的行为。至于原理之后会说明。如果你定义的是一个局部的锁,要对锁进行初始化需要使用下面到的函数。依旧使用destroy来销毁锁。下面我们来修改一下我们上面写的代码,让其变成一个使用局部锁的代码。代码如下:首先我们就要创建出一个局部的锁。然后修改我们之前封装的线程库,将这个锁作为参数
2024-03-19 12:54:33
912
原创 c++单例模式
后面启动的进程都是由前面的进程带起来的,就以bash为例子,创建的bash就可以说是最早的进程了,你将bash关闭了,很多的进程也就没有了。需要注意的就是这里的_inct是不存在于这个类对象中的,这里要将其放到类中是因为c++讲究的就是一个封装,封装的意思也就是管控,也就是要将这个_inst管控起来(收到访问限定符的限制)可以访问家人(private修饰的成员)。现在我们写的这个单例模式所对应的类,内部所包含的成员是很少的,但是在一个项目中,一个单例模式的类中所包含的成员一般是比现在的这个多的,
2024-03-04 07:41:30
1184
1
原创 System V版本的共享内存
在之前的学习中我们学习到了使用匿名和命名管道进行进程间的通信,下面我们再来使用一种新的方式进行进程间的通信。我们下面要学习的是system V版本的共享内存。首先我们要知道什么是system V首先我们要知道我们在之前学习的管道通信的代码并不是一个专门设计出来的模块,我们之前所学习的管道通信是复用了文件系统模块的代码的。但是我们在实际的使用场景上来说,只有一种通信方式是不够的。所以我们还是需要有其它的通信方式存在。由此就有人设计了一个专门用于进程通信的模块。
2024-02-27 07:00:00
1751
原创 管道通信(下)命名管道和简单日志函数的制作
在一个比较完善的服务运行过程中,肯定是会出现一些问题的,这些问题根据严重的程度不同我们的做法也是不一样的。常见的日志等级如下:info : 常规消息Warning:这个信息一般而言不会影响服务的运行,但是有必要要让用户知道,否则可能会造成某些问题的出现。Error :比较严重了,可能需要立即处理,但是也有可能这颗Error是不会影响我们的服务继续往下运行的。Fatal:致命问题,服务无法继续往下运行Debug:这个信息正常情况下我们不需要但是在调式的运行中会需要。这就是一般的日志等级的概念。
2024-01-15 12:23:47
1033
1
原创 管道进行进程间通信(中)(实现一个简单的进程池)
在上一篇的博客中我说明了一些关于管道的特征特点如下:其中对于3和4特征这里只需要知道即可,我会在后面的博客讲解。然后我们测试了管道的前三种情况:第一种:读写端正常,管道为空,读端就要阻塞.第二种:读写端正常,管道如果被写满,写端就要阻塞第三种:读端正常,写端关闭,那么读端就会读到0,表明读到了文件(pipe)结尾,但是此时的读端是不 会被阻塞的。
2024-01-08 09:20:10
995
原创 管道进行进程间通信(上)
首先一个文件是可以被一个进程打开并访问的,那么现在的问题是一个文件能否被多个进程打开并访问呢?如果能的话,那么这个文件不就是一个共享的空间吗?只要一个进程往这个文件中写数据,然后另外一个进程从这个文件中读取数据。不就实现了将一个数据从一个进程移动到另外一个进程上了吗?但是使用这种基于一个实体文件的方式有一个致命的缺点那就是,没写一个数据到文件中,这个数据就需要先刷新到磁盘上,然后再从磁盘将这个数据写到内存中,让另外一个进程读取这个数据。这样的方式就会伴生出很多的效率问题。但是我们可以借助这个思想。
2024-01-01 15:29:22
823
原创 动静态库的简单制作
以下就是两个小点我们知道.o文件在形成可执行程序的时候,要么使用的是动态连接,要么使用的是静态连接,那么我们如何去看呢?这里使用的是ldd命令。其中的第一行和第三行我们不需要理解第三行是Linux中的加载器,第二行是c标准库,但是为什么没有看到我们写的那个静态库mymath的连接呢?首先第一个gcc在连接程序的时候默认使用的是动态的连接。使用ldd也证明了这一点。我们的a.out这个程序可以执行说明在这个可执行程序中已经连接了我们的静态库。由此我们能够得到一个结论,
2023-12-27 10:57:28
1027
原创 文件系统和软硬链接(下)
在这里我们首先学习两个新的知识点第一个:第二个:下面我们再来理解思考下面的四个问题:我们首先来解决第一个问题如果新建一个文件Linux系统会做什么呢?
2023-12-18 21:21:26
921
原创 磁盘及文件系统(上)
这次博客我们将重点理解Ext2文件系统。首先我们要理解什么是文件系统。在之前我们一直理解的文件都是一个被打开的文件,而os为了能够管理这样的文件创建了struct_file这样的结构体对象在内核中描述被打开的文件,这个结构体对象中包含了被打开文件的基本属性,和绝大多数的属性(文件的大小,文件的偏移量,文件的权限,以及和内存块相关联的内容),包括对应的缓冲区。以上都是描述的被进程打开的文件的状态,那么没有被打开的文件?对于没有被打开的文件(磁盘中储存的文件)我们要关心下面几个关键。等等。
2023-12-16 15:35:12
904
原创 位图/布隆过滤器+海量数据处理总结
但是如果出现了4台服务器都无法完全储存这些信息了,需要扩展服务器,而为了不出现错误,所有用户信息的映射规则自然也是需要做出改变的,此时如果还是使用上面的哈希方法在扩展服务器的时候代价是很大的。解决思路就是:如果布隆过滤器最后返回的是不在代表此时的结果是准确的,不会做任何的处理,但是如果最后返回的是一个在,那么此时为了能够所有的结果都是准确的,这里选择的就是对布隆过滤器返回在的结果都交给服务器端在去做一个准确的判断,如果这个值在,那么这就是真的在了,如果这个值不在那么这个值就是不在。但是query不一样。
2023-11-27 11:22:32
616
原创 封装实现unordered_map和set
首先哈希是一个关联式容器,各个数据之间是具有关系的,和vector那些序列式容器不一样。首先unordered_map中的迭代器是一个单向的迭代器。其次在unorderede_map和set中是无序的(因为底层不是红黑树,而是哈希了)不再进行排序了。用法和set/map一样(除了不能使用--之外)。然后下面是对于map和unorder_ed map在性能上面的差异。
2023-11-20 15:22:58
149
原创 模拟实现一个Linux中的简单版shell
以上我们就能够完成一个比较简单的shell了,这里我们也知道了os中的shell也是一个进程,它能够不同的运行的原理是因为它是一个死循环,所以为了防止shell挂了,所以shell会创建子进程去完成用户输入的命令(如果shell不创建子进程执行命令,除了shell只能执行一次之外,还有shell会存在挂掉的风险,如果shell挂掉了,就没有软软件做命令行解释了),而因为每一个进程都是具有独立性的所以即使子进程挂了也不会影响shell的运行。这里需要注意的是argv是一个指针数组,而我们要获得的?
2023-11-16 16:55:39
1279
原创 红黑树插入节点的模拟实现
情况1:uncle节点存在为红(因为其它几个节点(gpc)的颜色是固定的,c为红色(新插入,或者下面调整上来{原因在上面说过了}),p一定是红色,那么g一定是黑色。情况2:uncle节点不存在/u存在为黑色我们来看情况2的第一种如果uncle是不存在的。此时的cur就是新增解决方式也很简单就是一个左旋(以g为轴)即可下面是情况2的第二种如果uncle是存在且为黑色的。此时的cur就不是新增了,因为cur的变色是在a或者b的下面新增然后通过变色不断影响上来的。下面我们假设右子树只存在u这一个黑色节点。
2023-11-12 12:29:12
249
原创 AVL树节点插入方式解析(单旋转和双旋转)
此时的抽象图就是对实际情况的归类,但是实际情况是存在无数种的,因为h可以等于0,1,2,3,4,5,6.当h等于2的时候,AVL树都存在三种,以下的三种都是可以放到abc,那三个位置的。但是这样打印出来一个升序的结果,只能证明这是一个搜索树,不能证明这一个AVL树,所以我们还需要些一个验证平衡的代码,即求出每一个节点的左右高度差(右子树高度减去左子树高度),如果不等于平衡因子,则证明我们的AVL树出现了错误。我们分开是因为虽然旋转的过程是一样的,到那时需要按照不同的情况,去处理不同的平衡因子。
2023-11-07 13:23:53
305
原创 map和set的使用
set是包含在头文件set中的首先我们来看一下set的原型:可以看到set的原型是一个类模板,而这里的第一个模板参数给了一个T,这就是我们在二叉搜索树那里学的key。然后Compare是一个仿函数,因为set的底层是一个搜索树,而搜索树是需要去比较key的大小的。然后最后一个是空间配置器。空间配置器是用于给容器申请内存的(我们暂时不用管),而仿函数内部已经默认有了一个所以我们也不需要管。所以我们在使用set的时候,只用给第一个即可。下面我们来看set的接口。
2023-10-31 18:27:54
147
原创 Linux中进程的控制(上)
这里我们引入一下:首先我们写一段会出现异常的代码:这里我们的代码除0错误会异常。此时编译运行一下会发现最后系统给我们报出了一个浮点数异常。还有一种这里不能写入是因为0号区域是属于代码段的,是不能写入的。这里的错误就是段错误。所以这里的程序崩溃了,本质就是进程异常了,而一旦进程异常了os是绝对不会继续让这个进程运行的。此时的这个进程只能被os杀掉。这也是为什么我们的异常代码无法运行的。那么这里os是如何杀掉进程的呢?其实当某一个进程异常之后,我们的os是通过信号的方式来杀掉我们的进程的。
2023-10-27 15:46:38
107
原创 模拟实现二叉搜索树(非kv模式)(上)
首先二叉搜索树肯定是一棵二叉树,对于二叉树我们应该是陌生了。而我们在学习二叉树的时候知道,如果只是一棵普通的二叉树,用来储存数据是没有任何意义的,因为如果我们将数据放到一个普通的二叉树上,那么当我们需要查找这个值的时候我们只能将整棵树都遍历一遍,我们才能找到这个这个节点在二叉树中的位置。这和我们普通的使用数组没有什么区别。二叉搜索树则不同二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
2023-10-25 08:06:09
99
原创 多态的使用以及多态底层的实现(下)
下图:对于第10,11,2,3问题在我的上一篇博客中说明了。希望这篇博客能对您有所帮助,如果您觉得写的不好请见谅,如果发现了任何的错误欢迎指出。
2023-10-23 22:04:50
244
原创 多态的使用以及多态底层的实现(上)
我们让不同的对象去完成同一件事情,这件事情的结果是不一样的,例如买火车票,我们学生买火车票,普通人买火车票,或是军人买火车票最后结果都是不一样的。这里需要记住的一点就是不构成重写就是重定义,因为重写和重定义的条件是存在相同之处的。可以说重写是在重定义的要求上关系可以看成下面的图:所以这里我们看父类和子类的函数名是否是相同的,如果相同就看是否是符合重写的要求,如果不满足那就是重定义。这里还要提出两个关键字第一个关键字就是final,这个关键字的作用是:修饰虚函数,表示该虚函数不能被重写。
2023-10-20 12:28:15
185
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人