自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(115)
  • 收藏
  • 关注

原创 跳表的设计与模拟实现

1.一开始就将哨兵节点的内存空间开辟好,防止之后出现高层节点时的扩容开销(既有空间上的,也有时间上的,扩容本质上是开辟一块更大的内存空间,同时对旧数据进行拷贝操作),但是这种其实只是用来考虑的,因为跳表本身最大层数就不会很大,就算不提前进行扩容,浪费的拷贝时间对比起业务来说也几乎可以忽略不计,一次查询数据库,或者一次网络通信,这种极少量数据的扩容产生的拷贝开销可以忽略掉,更何况扩容操作是永久性的,又不是这次扩了,下次又要扩,每一次都要拷贝数据(这个优化没有太多实际用处)我们再将上面的图拿下来分析下原因。

2025-12-21 15:12:46 834

原创 MySQL事务隔离

上面这种表就描述了各种隔离级别会出现的问题其中,这里出现的幻读,实际上本来应该是可重复读的隔离状态时会出现的问题。一般的数据库都没有解决这个问题这个问题实际上就是在进行insert操作时,就算隔离级别是可重复读,insert插入的数据也会被读取出来,这个问题叫做幻读,但是这很明显不符合可重复读,只不过MySQL已经解决了这个问题,采用Next-Key(GAP+行锁)来解决了这个问题。隔离级别越高,安全性也越高,并发效率也就越低,MySQL的默认隔离级别为可重复读,一般情况下不用修改。

2025-10-17 19:35:40 860

原创 MySQL事务机制

在上一篇文章,我们讲了索引机制,谈了两种不同的存储引擎的功能。我们提到MyISAM支持全文索引,而InnoDB支持事务。实际上,支持事务的是采用了InnoDB存储引擎的数据库或表。而MySQL的默认存储引擎采用InnoDB,也就是支持使用事务机制进行管理。

2025-10-16 22:29:42 737

原创 MySQL索引原理

最终,我们形成的结构就是这样的,每一级父节点,都存储目标page索引(大索引,也就是分隔,比如第二层是以20为分隔(0,20,40),下一层就以4为分隔(0,4,8)。设想,如果一个数据的数据量很大,如果我们将数据再次完完整整的复制一份,是不是非常的浪费空间,但是如果我们将数据采用主键索引的方式,再次去访问主键对应的B+树,就可以节省很多空间。我们从上面已经可以知道了B+树的结构是个什么样子,父节点存索引,叶子节点存数据,但这是B+树,还有一种树形结构,为B树,B+树实际上就是B树优化而来的。

2025-10-14 23:03:38 790

原创 图、最小生成树与最短路径

是该顶点的出度,也称出度表,要得到vi顶点的入度,必须检测其他所有顶点对应的边链表,看有多少边顶点的dst取值是i(也就是只有一张表存储的话,只有入读或出度的其中一个可以快速查找,另一个就很慢了,要遍历所有节点的连接关系)。如果他们的值为正,那么,他们的值实际上就是他的“上一层”元素的下标,有可能这个下标所对应元素的值为负,也就是集合最上层的元素所在位置。根据上面的图,我们可以发现,每一个属于同一个集合的元素,要不是他们自己,要不是他们所在的集合,都属于同一个集合当中,而他们所在的集合都以下标为单位。

2025-08-23 20:03:03 701

原创 多路转接epoll

2.如上面的例子, 由于只读了 1K 数据, 缓冲区中还剩 1K 数据, 在第二次调用epoll_wait 时, epoll_wait 仍然会立刻返回并通知 socket 读事件就绪。即:所有添加的事件都会与设备建立回调关系,当事件真的发生的时候,就会调用对应的回调函数,通知事件发生(该事件通过回调函数被添加到了epoll结构体中的双链表中)2.如上面的例子, 虽然只读了 1K 的数据, 缓冲区还剩 1K 的数据, 在第二次调用epoll_wait 的时候, epoll_wait 不会再返回了。

2025-08-15 19:33:23 847

原创 高并发HTTP服务器设计

1.字符串分割:根据指定字符串对源字符串进行分割,并将分割后的元素放入数组中2.读取文件内容3.写入文件4.URL编码(除一些特殊字符、字母、数字外,uri部分其他字符(主要是中文)要修改为"%HH"的16进制格式,空格修改为'+')5.URL解码(实际上服务器要做的是解码这一步,编码是浏览器发送给服务器时就已经完成了的)6.响应状态码描述的获取7.根据文件后缀判断文件类型8.判断文件是普通文件还是目录9.判断文件路径是否是一个合法的路径(主要是是否访问到了服务器工作目录的上一级目录)

2025-08-11 16:51:08 775

原创 多路转接select

系统提供 select 函数来实现多路复用输入/输出模型1.select 系统调用是用来让我们的程序监视多个文件描述符的状态变化的2.程序会停在 select 这里等待, 直到被监视的文件描述符有一个或多个发生了状态改变。

2025-08-03 11:10:06 951

原创 5种IO模型与阻塞IO

为了完成任务而创建的多个进程/线程需要一定的工作次序,我们需要让他们按照某种次序去而等待,传递信息,尤其是访问共享资源的时候,我们为了实现同步而采用的方法为互斥,一个资源在同一时间最多只能被一个进程/线程访问到。我们采用异步通信,使用的是非阻塞的方式,我们当前并不紧急需要该调用的结果,我们接下来执行其他方法即可,在调用结果处理完之后会通知程序,我们只需要在结果处理完之后直接拿到结果即可,这种方式就是非阻塞。实际的场景中,等待所消耗的时间远远多于拷贝的时间,所以提高效率的办法就是尽量减少等待的时间。

2025-07-31 10:47:54 573

原创 NAT技术与代理服务

反向代理服务器是一种网络架构模式, 其作为 Web 服务器的前置服务器, 接收来自客户端的请求, 并将这些请求转发给后端服务器, 然后将后端服务器的响应返回给客户端。这种架构模式可以提升网站性能、 安全性和可维护性等。

2025-07-30 11:22:22 1127

原创 数据链路层

MSS和MTU的关系就是,MSS规定了tcp协议中存放数据的最大消息长度,而MTU则是在MSS基础上再加上了tcp数据报头与ip数据报头,要求MSS+tcp报头长度+ip报头长度在(46,1500)这个范围之内,因为MTU对应的数据本就是整个上层一直封装到网络层的全部数据,而MSS则只是应用层发出的数据,甚至不包括报头。上面我们也讲过了,ip地址与mac地址的范围不同,范围更大的ip地址标识的是路途的起点与终点,也就是整个传输过程中的起点主机与目的主机。

2025-07-30 10:47:40 1017

原创 IP协议解析:从寻址到路由

在复杂的网络环境中确定一个合适的路径主机:配有IP地址但能进行路由的设备路由器:配有ip地址,又能进行路由控制的设备节点:主机与路由器的统称。

2025-07-28 17:29:58 696

原创 传输层协议TCP

原因就是上面四次挥手时,主动断开连接的一方会进入TIME_WAIT状态,我们上面也说了,TIME_WAIT状态需要过一段时间才能够转为CLOSED状态,也就是说此时实际上TCP连接相当于并没有断开,所以我们尝试绑定时无法绑定一个已经存在的地址与端口号。MSL 是 TCP 报文的最大生存时间, 因此 TIME_WAIT 持续存在 2MSL 的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启, 可能会收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的);

2025-06-24 21:14:28 1180 1

原创 传输层协议UDP

答案是一般情况下是不可以的,但是我们可以手动设置,比如说我们在前面TCP编程里面写过setsockopt,这个函数就可以让我们的套接字修改为可重用端口号,当然,如果我们不指定的话就没办法绑定一个已经被别的套接字绑定过的端口号了,一旦我们指定了SO_REUSEPORT,那么这个套接字就可以绑定一个已经被绑定过的端口号了,我们在多个进程里都写这么一个套接字,那么我们就可以让多个进程绑定同一个端口号了。0~1023:知名端口号,HTTP, FTP, SSH 等这些广为使用的应用层协议, 他们的端口号都是固定的。

2025-06-23 20:21:23 1047

原创 应用层协议HTTP

HTTP(超文本传输协议)定义了客户端(如浏览器)如何和服务器进行通信的超文本客户端向服务器发送请求,服务器收到请求,处理后给客户端返回响应。HTTP是一个无连接无状态协议,也就是说每次都需要重新建立连接,且服务器不会保存客户端状态。

2025-06-20 17:16:20 860

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

我们写的一个个用来解决我们实际问题的程序都是在应用层。

2025-06-19 20:09:20 346

原创 Socket编程TCP

我们前面写过UDP,我们这次写TCPUDP的话可以看出来1.发送方就是创建套接字,向某台主机的某个端口port发送消息2.接收方也是创建套接字,获取发向当前port的消息。

2025-06-18 22:23:37 676

原创 Socket编程udp

1.首先创建socket文件,最后一项默认为0即可,第一项为ip类型,ipv4还是ipv6,ipv4为AF_INET,ipv6为AF_INET6。头文件中,IPv4地址用sockaddr_in结构体,包括16位地址类型,16位端口号与32位IP地址。tcp协议为面向字节流,我们这里是udp协议,面向字节流,采用SOCK_DGRAM。第二项端口号,由于是服务器,端口号不可变,因此我们在前面就已经确定好了默认端口号。第三项ip地址,我们可以手动选择本地地址或者网络地址,当然,我们也可以选择填入。

2025-06-17 21:45:14 688

原创 线程同步与互斥

大佬们对一些经典常见场景给出的一些对应解决方案,就叫设计模式某些类,应该只有一个对象(实例),称为单例模式,例如上面使用的日志类其实使用的一直都只有一个logger类,我们就可以给他设计为单例模式。在很多服务器开发场景中,经常要让服务器加载几百g的数据到内存中,此时往往需要使用一个类来管理这些数据。

2025-06-04 22:32:46 883

原创 线程概念与控制

1.在⼀个程序⾥的⼀个执行路线就叫做线程(thread)。更准确的定义是:线程是“⼀个进程内部的控制序列”2.⼀切进程至少都有⼀个执行线程3.线程在进程内部运行,本质是在进程地址空间内运行4.在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化5.透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程控制流。

2025-05-31 22:49:36 842

原创 Linux进程信号

三种。

2025-05-31 17:13:01 1440

原创 进程间通信

1.先使用ftok根据实际路径与标识符创建一个唯一的键值2.将键值 key交给shmget来创建或者是获取一个共享内存的标识码shmid3.将shmid交给shmat来为进程设置一个指针用来访问共享内存区域4.当前进程不再需要该共享内存时使用shmdt来解除与该共享内存的关系5.所有进程不再需要该共享内存时调用shmctl来删除共享内存。

2025-05-30 19:13:49 1225

原创 动静态库的制作

本质上来说库是⼀种可执行代码的⼆进制形式,可以被操作系统载入内存执行。可分为两种:静态库:.a(linux)、.lib(windows)动态库:.so(Linux)、.dll(windows)

2025-05-28 21:09:31 468

原创 Ext系列文件系统

扇区:是磁盘存储数据的基本单位,512字节,块设备我们访问文件时是访问具体某一个扇区的内容磁盘容量=磁头数×磁道(柱⾯)数×每道扇区数×每扇区字节数定位文件只需要确定磁头(高),柱面(自内而外第几个),扇区(某一磁道的具体位置)即可。我们可以想象扇区是一个个连起来的,那么我们就可以通过下标去访问了某一磁道展开就可以形成下面的一个个连起来的扇区某一柱面展开,就可以形成这种[盘面某磁道][扇区]的二维数组然后再加上许许多多的柱面,我们就可以形成:[某一柱面][某一磁道][扇区]

2025-05-26 17:57:09 1014

原创 基础IO(linux)

读写⽂件时,如果不会开辟对⽂件操作的缓冲区,直接通过系统调⽤对磁盘进⾏操作(读、写等),那么 每次对⽂件进⾏⼀次读写操作时,都需要使⽤读写系统调⽤来处理此操作,即需要执⾏⼀次系统调 ⽤,执⾏⼀次系统调⽤将涉及到CPU状态的切换,即从⽤⼾空间切换到内核空间,实现进程上下⽂的 切换,这将损耗⼀定的CPU时间,频繁的磁盘访问对程序的执⾏效率造成很⼤的影响。因为标准 I/O库每⾏的缓冲区⻓度是固定的,所以只要填满了缓冲区,即使还没有遇到换⾏符,也会执⾏ I/O系统调⽤操作,默认⾏缓冲区的⼤⼩为1024。

2025-04-04 16:48:59 1223

原创 进程概念(3)

在两个队列之中一共存放140个优先级,前面100个存放系统进程,而我们创建的进程则属于后40个优先级,通过修改nice值使我们的进程在[100,139]范围内。同时,新增加的进程只会放入过期队列中而不会放入活跃队列,这样可以保证活跃队列中的进程始终在减少,保证之后所有进程的运行。而当活跃队列中所有进程都执行完后(时间片到期或运行完成),则将活跃队列与过期队列进行交换即可。当某一进程时间片到了却仍未完成任务时,则会将该进程从活跃队列放到过期队列中。作为传给main的参数,继承父进程的环境变量。

2024-11-05 11:59:32 247 1

原创 linux进程概念(2)

当然,除了以上三种状态之外还有一个挂起状态,当内存严重不足时,操作系统会将阻塞状态的进程放入到磁盘中来缓解内存不足,当有数据输入时再运行。只有被回收了退出码的进程才会被销毁,而没有被回收的进程则会进入僵尸状态,僵尸状态为:代码和数据被销毁,但是进程的内核数据结构还在,只有回收退出码才能完全销毁进程。在中有两种队列,一种为runqueue(运行队列),一种为waitqueue(等待队列),当进程处于运行队列时即为运行状态,处于等待队列即为休眠状态(阻塞)

2024-11-04 14:30:46 1021

原创 linux进程概念(1)

我们再举个例子,以水果市场为例,每种水果都有对应的价格,名称,数量等属性,商家可以创建fruit结构体对水果的属性进行描述,再通过链表来对各种水果进行管理,那么对水果的增删查改,即可转变为对链表的增删查改。对上,用户通过用户操作接口,或采用图形化界面,或采用命令行操作的方式来调用系统接口,由操作系统进行堆内存,进程,文件,驱动进行统一管理。在进程中存在pid这一概念,pid为某进程的编号,ppid为某进程父进程的编号,子进程由父进程创建,所有的命令也都是一个进程。

2024-11-03 15:21:40 656

原创 linux基础工具

我们有两种做法,一种是直接gcc -o test test.c生成可执行文件,这里为了演示,我们从ESC指令开始一个个生成,由上到下,我们可以发现,test文件需要.o文件,.o文件需要.s文件,由此开始向下不断查找,直到最后.i文件需要.c文件,而.c文件就在当前目录下,因此我们可以从这一行命令开始逐渐往上执行直到生成目标的test文件。我们可以发现无法被执行,因为test已经是最新的了,这个原因是每个文件都有时间属性,分别为内容被修改的最新时间,属性被修改的最新时间和程序被执行的最新时间。

2024-11-02 13:08:35 707

原创 C++的IO流

在C语言中,如果想要将一个整形变量的数据转化为字符串格式,如何去做?1. 使用itoa()函数2. 使用sprintf()函数但是两个函数在转化时,都得需要先给出保存结果的空间,那空间要给多大呢,就不太好界定, 而且转化格式不匹配时,可能还会得到错误的结果甚至程序崩溃。在C++中,可以使用stringstream类对象来避开此问题。在程序中如果想要使用stringstream,必须要包含头文件。

2024-10-14 17:24:38 1062

原创 C++的类型转换

强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是 否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用 域,以减少发生错误的机会。强烈建议:避免使用强制类型转换。在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与 接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型 转换和显式类型转换。缺陷: 转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换。

2024-10-14 17:02:34 497

原创 特殊类设计

后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后 来孙子就总结出了《孙子兵法》。比如在某个服务器程序中,该服务器的配置 信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再 通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取 文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化, 就会导致程序启动时非常的缓慢。

2024-10-14 16:48:06 1191

原创 智能指针(cpp)

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内 存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对 该段内存的控制,因而造成了内存的浪费。内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现 内存泄漏会导致响应越来越慢,最终卡死。// 1.内存申请了忘记释放// 2.异常安全问题Func();// 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.

2024-10-14 16:35:57 1044

原创 C++(异常)

实际使用中很多公司都会自定义自己的异常体系进行规范的异常管理,因为一个项目中如果大家 随意抛异常,那么外层的调用者基本就没办法玩了,所以实际中都会定义一套继承的规范体系。这样大家抛出的都是继承的派生类对象,捕获一个基类就可以了// 服务器开发中通常使用的异常继承体系public:,_id(id){}protected:int _id;public:{}

2024-10-07 20:38:27 1177 3

原创 C++11

可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对 象来“适应”原对象的参数列表。我们无法直接获取参数包args中的每个参数的, 只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特 点,也是最大的难点,即如何展开可变模版参数。随着C++语法的发展,人们开始觉得上面的写法太复杂了,每次为了实现一个algorithm算法, 都要重新去写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名, 这些都给编程者带来了极大的不便。

2024-10-06 21:21:12 1100

原创 C++11(声明,STL变化与左右值)

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋 值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左 值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。int main()// 以下的p、b、c、*p都是左值int b = 1;// 以下几个是对上面左值的左值引用return 0;

2024-09-28 17:02:28 994

原创 哈希的模拟与应用

线性探测的缺陷是产生冲突的数据堆积在一块,这与其找下一个空位置有关系,因为找空位 置的方式就是挨着往后逐个去找,因此二次探测为了避免该问题,找下一个空位置的方法 为:$H_i$ = ($H_0$ + $i^2$ )% m, 或者:$H_i$ = ($H_0$ - $i^2$ )% m。桶的个数是一定的,随着元素的不断插入,每个桶中元素的个数不断增多,极端情况下,可 能会导致一个桶中链表节点非常多,会影响的哈希表的性能,因此在一定条件下需要对哈希 表进行增容,那该条件怎么确认呢?键和映射值的类型可能不同。

2024-09-23 21:48:10 940

原创 AVL树与红黑树

{}// 该节点的左孩子// 该节点的右孩子// 该节点的双亲T _data;int _bf;// 该节点的平衡因子// 节点的颜色// 红黑树节点的定义{}// 节点的左孩子// 节点的右孩子// 节点的双亲(红黑树需要旋转,为了实现简单给出该字段)// 节点的值域// 节点的颜色。

2024-09-22 18:59:12 942

原创 map与set

1. map中的的元素是键值对2. map中的key是唯一的,并且不能修改3. 默认按照小于的方式对key进行比较4. map中的元素如果用迭代器去遍历,可以得到一个有序的序列5. map的底层为平衡搜索树(红黑树),查找效率比较高O(log2 N)6. 支持[]操作符,operator[]中实际进行插入查找。

2024-09-13 22:36:12 992

原创 二叉树进阶

比如:给一个单词word,判断该单词是否拼写正确,具体方式如下: 以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二 叉搜索树的深度的函数,即结点越深,则比较次数越多。情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点 中,再来处理该结点的删除问题--替换法删除。3.它的左右子树也分别为二叉搜索树。

2024-09-09 14:55:25 877

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除