- 博客(71)
- 收藏
- 关注
原创 C++ set && map
既然set和map的底层采用红黑树,那就少不了我们之前实现过的红黑树,直接搬过来复用但我们实现的红黑树是Key-Value模型,难道要针对Key模型再copy一份红黑树,将节点里面的值修改成Key吗?STL 中采用模板的方式,只需要一份红黑树,就能完成Key和Key-Value模型的统一既然如何,红黑树节点的定义中,数据就不能只是key或pair对象,而应当是泛型,外部传递什么类型,数据就是什么类型,_col(RED){}T _data;Color _col;// set.h。
2025-03-31 21:26:10
779
原创 高并发内存池
该项目的原型是Google的开源项目tcmalloc,tcmalloc全称Thread-Caching Malloc,即线程缓存的malloc,实现了高效的多线程内存管理,用于替代内存分配函数malloc和free我们将tcmalloc的核心框架提取出来,模拟实现一个简单版本的高并发内存池,目的是学习tcmalloc的精华。
2025-03-22 00:07:41
615
原创 Reactor
Reactor类似于一种Connection的容器,当底层事件就绪,进行事件派发,让不同的Connection的去处理事件Reacotr是基于事件驱动的网络服务器设计的主流模式。
2025-02-12 22:03:47
876
原创 多路转接-
我们往标准输入里输入的数据是有序的,只不过一旦标准输入有数据,OS就会拷贝一份给标准输出,这也称为"回显",同时,进程也往标准输出发送数据,所以标准输出刷新到显示器上时,数据混杂在一起。对于现在的CPU,拷贝的速度非常快,关键在于"等",如果数据,就要一直等,所以,高效的IO就是单位时间内降低等的比重。要想提高IO的效率,就要降低单位时间内等的比重,于是,就有专门的系统调用来帮我们"等",等底层数据就绪了,再通知上层,这样。上的新事件就绪,通知上层,可以进行拷贝了,这里的新事件指的是底层有数据/空间了。
2025-01-23 14:43:19
756
原创 NAT && 代理服务器
其次,在云服务器上部署一种服务,该服务将所有发送到云服务器指定端口的报文全部转交给B,由B处理报文并将应答返回给云服务器,再由云服务器将应答返回,这样就完成了两个私网之间的通信,我们把这种技术叫做内网穿透。以Windows作为client,连接云服务器上的服务,发送消息,将源主机的IP地址打印出来,会发现打印出来的IP地址与Windows主机的IP地址不同。有时,我们也需要远程办公,比如B是你家中的主机,A是你在出差地的主机,这样就能在远方访问到家中的主机,完成工作。
2025-01-10 15:49:50
1013
原创 数据链路层
如果发送的报文长度过长,占用局域网的时间也就越长,其他主机也更有可能在这时发送报文,发生碰撞的概率也就越高,这也是为什么数据链路层要限制IP数据报的最大长度,有MTU的原因,从而需要IP进行分片,TCP进行滑动窗口内数据多次分发。局域网内的主机经过多轮通信,交换机知道了所有主机的位置后,此时A要给D发送报文,交换机收到后,判断D在i0侧,于是不会将报文通过i1接口转发出去,C给E发送报文,也不会被转发给i0侧,于是A->D,C->E就在同一时刻完成了通信。同一局域网中的主机能直接通信吗?
2024-12-30 19:29:35
1087
原创 ip-协议
这时,网络层就对传输层说了,如果你给我交付的数据过大,我必须得进行分片,这样会导致丢包概率变大,从而你就要超时重传,对双方都是不利的;IP报文的总长度可能16位的,最大可能2^16字节,此时用13位偏移量来表示后面分片的偏移量,是存不下的,因此,13位偏移量真实存的值是偏移量 >> 3,这也是为什么偏移量必须是8的倍数。负责人一定知道每个院的负责人是谁,也知道每个院的院号,根据按位与的结果,判断学生一定是计院的,于是就交给计院的负责人,计院的负责人在它们的计院群通知,于是,学生证也就物归原主了。
2024-12-26 20:53:54
1024
原创 udp && tcp协议
拿上图举例,如果最左边报文丢失,接收方在对其他报文进行应答时,根据确认序号的定义,只能填0,因为1000的报文没收到,当发送方收到3个以上的相同应答,触发快重传机制,立即补发1000的报文,接收方可以直接ACK4001,表示4000之间的报文已经收到。通信模式中,常见的是第二种,多个报文一并发送时,由于报文是经过网络传输的,它们走的线路不同,到达对方主机的时间也就不同,也就意味着发送的报文可能是有序的,但接受时可能是无序的,此时,OS会根据报文的序号来排序,确保向上层交付的数据是有序的。
2024-12-24 20:21:47
1157
原创 http协议
将明文通过密钥转换成密文的过程就称为加密将数据进行哈希算法,形成一串几乎具有唯一标识字符串,将该字符串就成为数据摘要或者数据指纹如果原来的数据被修改,哪怕是一点点,经过同样的哈希算法所形成的字符串一定不一样,可以借此判断原数据是否被篡改数据摘要的应用:云盘的秒传功能用户数据的存储。
2024-12-23 09:27:04
988
原创 应用层自定义协议
实际上,一次发送的数据不一定是一条,有可能是不到一条或多条,同理,从接受缓冲区读上来的数据也可能不是一条,我们就需要对读上来的数据进行处理,确保它是一条报文。库来进行,如果要我们自己实现,原则上需要处理各种数据,但这里我们简单化,只是为了帮助我们理解序列化与反序列的过程,在工作中,我们也不会手动序列化和反序列。当数据放到接受缓冲区中,用户就不再需要管这些数据了,至于数据如何发送,一次发送多少,发送错误怎么办,这些问题都交给传输层决定,这也是为什么。当获取新的连接,创建线程,让线程。
2024-12-07 16:10:49
769
原创 Socket编程-tcp
在tcp套接字编程这里,我们将完成两份代码,一份是基于tcp实现普通的对话,另一份加上业务,client输入要执行的命令,server将执行结果返回给client。
2024-12-06 11:38:11
1023
原创 Linux 网络基础
我们也可以尝试从操作系统的角度理解局域网通信:所有主机的数据是发向以太网的,这里的以太网是不是就相当于操作系统中的临界资源,任何时刻,只能有一台主机向网络中发送数据,不就相当于任何时刻只能有一个线程访问临界资源,因此需要对临界资源加锁,对应网络中我们需要进行碰撞检测和碰撞避免。这好比上课时,老师说:“A,你起来回答这个问题”,此时,班里的所有同学都收到这条信息,每个同学将信息的目的地址与自身对比,发现不是自己,也就不做处理,而A做对比之后,发现是自己,于是做出回应。
2024-12-04 11:14:25
711
原创 Socket编程-udp
最先使用udp进行socket编程,最直接的原因就是因为udp简单,方便我们快速熟悉socket各种系统调用我们一共会完成三份代码,第一份我们会实现两台主机之间的简单聊天系统;第二份在第一份的前提下,我们加上一个翻译的业务,当client向server发送一个英文单词,server会给client返回该单词的中文意思;第三份在第一份的前提下,实现简单的群聊系统。
2024-12-03 12:20:14
1006
1
原创 Windows客户端无法与Linux服务通信
想使用Windows下的客户端(如VS)与Linux的服务进行通信,或者用浏览器向Linux发送http请求,连接失败。
2024-08-26 14:32:00
633
原创 C++ 多态篇
子类对象会将父类的虚函数拷贝到自己的虚表中,并检查是否完成虚函数的重写,如果完成,将虚函数覆盖为自己的虚函数,当使用父类的引用/指针去调用虚函数时,由于发生切片,如果指向父类,去调用父类的虚函数,如果指向子类,去调用子类中父类部分的虚函数,这就是多态的原理。在多继承中,子类中有两个虚表指针,分别在A类的部分和B类的部分中,A类的部分继承A类的虚函数,B类的部分继承B类的虚函数,再看是否完成重写,有就拿自身的覆盖;不可以,虚表指针在构造函数的初始化列表中初始化,如果构造函数时虚函数,虚表指针就无法初始化了。
2024-07-06 19:50:40
1089
原创 Linux 进程信号篇
此时,该进程的时间片到了,要进行进程切换,我们知道进程切换最重要的就是寄存器需要保存和恢复进程的上下文数据,它也照常这样做,将10和0保存好,下次调度时再恢复,这时大家就应该明白了,下次调度时,运算的还是10/0,溢出标记位置1,OS向进程发送信号,如此往复,就出现了死循环打印。以我们现在的知识,理解上面的问题十分容易,程序崩溃是因为我们进行了非法的访问或操作,OS向进程发送了信号,该信号的默认动作是终止进程,因此我们的程序直接退出了,最典型的有Floating-point exception(
2024-06-30 15:35:59
1172
原创 C++ 继承篇
有这样的场景,你要完成一个学生管理系统,必然需要描述很多的对象,于是构建很多类,每个类代表不同的群体,比如学生类、老师类、宿管类…定义出来后,发现每个类中都有某些属性是相同的,比如大家都有名字、年龄、性别这样的属性,在每个类中都定义了一遍,显然代码冗余,于是就有了继承将每个类的公共属性提取出来,单独作为一个类,称为父类/基类;每个群体中持有它们独有的属性,叫做子类/派生类,通过继承的方式,将父类继承给子类,这样子类就有父类的属性和自身独有的属性。
2024-05-08 16:46:58
941
原创 Linux 基础IO篇
函数以w而Linux中输出重定向的行为跟fopen以w的方式打开文件类似,追加重定向>>跟a的方式类似,由此我们知道和>>一定是进行了文件操作,它们之间有啥关系?这是我们接下来要讨论的问题。
2024-05-06 23:26:51
1317
原创 Linux进程控制篇
进程 = 内核的相关管理数据结构(tack_struct + mm_struct + 页表) + 代码和数据由于进程具有独立性,父子进程的内核数据结构各自独有一份;代码是可读的,父子共享;数据根据写时拷贝,分配给子进程一个进程,在内存中,先有它的内核数据结构,再有它的数据和代码。
2024-04-16 16:12:51
992
原创 C++ vector
vector是 C++ STL 中的一个类模板,它是一个动态数组;本篇文章只模拟实现常用的接口,与库中实现的相比,功能类似,但实现方式并不相同。
2024-04-06 17:09:16
794
原创 Linux进程概念篇
进程的优先级是进程的控制块task_struct中的一条属性,它代表着该进程获取某种资源的先后顺序;优先级的值越小,代表着优先级越高权限规定的是能不能访问某种资源;优先级则是已经能访问了,规定的是访问的顺序。
2024-04-01 15:54:29
619
原创 C++String类
String是C++中操作字符串的类,它是在比较早的时候设计的STL模板,因此在某些地方设计的有些冗余对于String类,不仅仅是学会使用它,更重要的是要从底层去理解它;本篇文章将从底层出发,模拟实现常用的String类接口(实现方式与不同平台下的标准库中的实现不一定相同)
2024-03-24 22:56:22
601
原创 C++模板篇
C语言中,想实现不同类型数据的交换,我们得实现针对不同类型的交换函数,每个函数的实现细节又很类似,显示很繁琐;有没有一种通用交换函数,能适用所有类型的交换C++中,提供了模板的概念,我们只需要提供一个模板函数,编译器就会根据传参类型自动推导出函数编写与类型无关的通用代码,也称为泛型编程。
2024-03-12 10:53:30
313
2
原创 C++内存管理篇
在某些场景下,我们向内存申请的空间没有初始化,比如向内存池申请的空间,如果是自定义类型的对象,我们可以使用new的定义表达式进行显示调用构造函数进行初始化。C++中,这些函数依然可用,但在使用上是比较麻烦的;C++语言中,我们用malloc/calloc/realloc/free函数进行内存的开辟和释放,对内存进行管理。可以看到,new和delete的最底层还是使用的malloc和free函数,只不过是对它进行了一系列封装。C语言中,为了方便管理内存空间,将内存分成了不同的区域,每个区域管理不同的数据。
2024-03-09 22:34:52
1237
1
原创 Linux工具篇
makefile会从上往下执行代码,如果某段代码没有对应的依赖文件,会暂时记录该代码,往下寻找对应的依赖文件,最后再依次返回,有点像递归的操作;想要在内存和文件之间传输数据,一次传输的数据量越多,传输的次数越少,传输的效率也就越高,而如果传输的数据过多,又不方便我们阅读,因此以行作为刷新缓冲区的标志是一种即提高效率,又方便阅读的做法。答案是否定的,在Linux中也是如此,想要下载的软件包在机器的远程服务器上,yum通过本地的yum源找到远程服务器,再在服务器中找到对应的软件包,下载到本地机器,再安装下来。
2024-03-03 23:31:45
1075
1
原创 C++类和对象篇
函数的声明和定义都在类中class Datepublic:private:int _year;int _month;int _day;函数的声明在.h文件中,定义在.cpp文件中,此时定义函数时必须指定类域//Date.hclass Datepublic:private:int _year;int _month;int _day;//Date.cpp。
2024-02-26 20:07:32
1060
原创 牛客网BC12-字符圣诞树
字符圣诞树解题思路:确定行数,一共5行,循环5次确定每行答应的内容,分成两部分,空格和字符打印空格的个数依次递减打印字符的个数依次递增找出打印空格和字符的个数与行数之间的关系
2024-01-06 19:52:07
552
2
原创 atoi函数的模拟实现
有时候返回的值可能是正常的,也有可能是异常的,但和正常值在数值上是一样的;就比如空字符串,此时返回0,而atoi(“0”)也是返回0,那么0到底空字符串返回的异常值,还是转换后返回的正常值呢?于是,我们定义一个枚举类型,并用该类型创建一个变量,默认值是异常值,如果atoi函数结束时,该变量是异常值,表示返回的值是异常的,否则是正常的。写代码时,我们要考虑周全,写出来的代码不仅仅是完成我们预期的结果,还要能处理各种异常情况。对于一个只有数字字符的字符串,怎么将该字符串转换成对应的整数?
2024-01-05 20:56:32
459
1
原创 动态内存管理篇
为什么要动态内存分配?之前,我们向内存申请空间,有两种方式,一种是定义变量,一种是建立数组;但是,这两种方式都有缺陷,创建的空间大小是固定的,在程序的运行过程中,不能随着我们的需要改变而改变,这就需要我们申请动态内存了内存非为三大部分,动态内存函数申请的空间是在堆上开辟的动态开辟的内存用完了,想进行增容,这时就可以考虑使用realloc用realloc开辟完空间,更推荐使用写法2,因为realloc开辟空间可能会失败,此时返回NULL,不仅没有扩容成功,还把原来的空间给弄没了。
2024-01-01 18:08:27
990
1
原创 自定义类型篇
其中有些数据很小,是完全不需要char或int来存储,这时就用到我们的位段了,如果用结构体存储,数据包就会比较大,在网络中流动的也就慢。另外,我们最好拿枚举常量给枚举变量赋值,如果给枚举常量赋值其他类型,有些编译器是不会报错的,但这样枚举就失去了意义,要赋整型值,为什么不直接定义整型变量呢?我们的结构体大小可能是很大的,这种情况下使用传值调用,还得再开辟一块一样大的空间,对于栈帧的消耗是非常大的;可以发现,联合体s的地址,联合体的成员a,b的地址,三者是一样的,也就是说变量b和a使用了同一块空间。
2023-12-29 14:01:44
962
3
原创 指针进阶篇
要同前面的指针数组区别开,数组指针本质上是一个指针,该指针指向一个数组。拿这个代码举例,我们想要将该数组的地址存一个指针当中,得到的那个指针就是一个数组指针。要完成这个操作,需要解决两个问题。1.怎么取出数组的地址?2.数组指针的类型改怎么写?对于第一个问题,我们先来梳理一下数组名的概念:sizeof(数组名):表示整个数组的大小,单位是字节&数组名:表示取出整个数组的地址到这里,第一个问题就解决了,要得到一个数组的地址,只需要&数组名就行了。//错误的写法。
2023-12-16 22:36:34
1186
2
原创 排序算法(详解)
排序在日常生活中十分重要,购物平台上商品的排序,各国高校等级的排序......可以说,现代生活中已经离不开排序了;因此学好排序算法至关重要,本篇文章就来讲讲常见的排序算法排序的种类非常多,按照种类划分,有插入排序,选择排序,交换排序......,而每种排序中又分多种排序,下图是常见的排序算法。
2023-12-14 16:34:41
2373
5
原创 Linux权限篇
生活中,有些事情你不能做,别人能做,这叫别人有做某事的权限;Linux中,权限的概念也是类似的,特指通过一定的条件,拦住一部分人,给另一部分人权限去访问资源。
2023-12-11 23:42:02
918
4
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人