自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(212)
  • 问答 (2)
  • 收藏
  • 关注

原创 HTTPS建立连接过程

为了保证传输的内容不被篡改,我们需要对内容计算出一个指纹,然后同内容一起传输给对方。对方收到后,先是对内容也计算出一个指纹,然后跟发送方发送的指纹做一个比较,如果指纹相同,说明内容没有被篡改,否则就可以判断出内容被篡改了。那么,在计算机里会用摘要算法(哈希函数)来计算出内容的哈希值,也就是内容的指纹,这个哈希值是唯一的,且无法通过哈希值推导出内容。通过哈希算法可以确保内容不会被篡改,但是并不能保证内容+哈希值不会被中间人替换,因为这里缺少对客户端收到的消息是否来源于服务端的证明。

2025-03-16 20:57:55 598

原创 HTTP协议简介

通过F12打开浏览器的开发者工具,点击Network标签页,然后刷新页面。显示的每一条记录都是一次HTTP请求/响应抓包工具,这里以Fiddler为例,它能够直接读取你电脑上网卡的信息,网卡上有什么数据流动,它都能够感知到并且显示出来。平时我们俗称的”网址“,其实就是 URL(Uniform Resource Locator),翻译为统一资源定位符互连网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它当我们用搜狗搜索时,通过抓包,我们会得到下面这个URL。

2025-03-15 20:24:42 891

原创 基于muduo+mysql+jsoncpp的简易HTTPWebServer

该WebServer基于muduo网络库与HTTP协议栈,muduo网络库主要负责socket连接的管理以及数据的管理,而在连接建立时,在连接的上下文context中初始化HTTPcontext,然后在接收到HTTP请求时,通过调用onMessage回调函数将接收到的数据保存在连接的HTTPcontext中并且处理HTTP请求,然后通过onRequest回调函数根据请求生成HTTP响应,在哈希表(与数据库同步)中获取所有车牌返回对应的HTML页面。

2025-03-10 21:34:33 978

原创 Reactor模型

重要组件:Event事件、Reactor反应堆、Demultiplex事件分发器、Eventhandler事件处理器。

2025-03-02 15:47:57 237

原创 P2P网络打洞技术解析

在传统的集中式网络中,都是一台服务器(集群)对外提供服务,所有客户端都依赖中央服务器进行与服务端的通信或者其他客户端的通信。如图这样的通信方式,一个数据包从一个客户端发送到另一个客户端都要在服务端中进行中转,服务端承受的压力非常大,很容易因为线程问题而当机。于是提出另一种通信方式:P2P通信(peer to peer)对等通信。

2025-02-19 20:50:00 934

原创 什么是一致性哈希?

比如,上图中如果节点A被移除了,当节点A宕机后,根据一致性哈希算法的规则,其上数据应该全部迁移到相邻的节点B上,这样,节点B的数据量、访问量都会迅速增加很多倍,一旦新增的压力超过了节点B的处理能力上限,就会导致节点B崩溃,进而形成雪崩式的连锁反应。最简单的方式,引入一个中间的负载均衡层,让它将外界的请求轮流的转发给内部的集群。比如,当某个节点被移除时,对应该节点的多个虚拟节点均会被移除,而这些虚拟节点按顺时针方向的下一个虚拟节点,坑会对应不同的真实节点,即这些不同的真实节点共同分担了节点变化导致的压力。

2024-08-24 22:20:59 1115

原创 哈希(Hash)

哈希也叫散列,因而哈希表也叫散列表。通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做哈希函数。采用散列函数将记录存储在一块连续的存储空间中,这块连续的存储空间称为哈希表。所得的存储地址称为哈希地址。

2024-08-20 21:22:20 2213

原创 从编程语言到可执行程序

动态库还有另外的强大之处,那就是如果修改了动态库的代码,我们只需要重新编译动态库即可,而不需要重新编译依赖该动态库的程序,因为可执行文件当中仅仅保留了动态库的必要信息,只需要简单地用新的动态库替换原有动态库即可,下一次程序运行时就可以使用最新的动态库了。第一种场景,在程序加载时进行动态链接,这里的加载指的是可执行文件的加载,其实就是把可执行文件从磁盘搬到内存的过程,因为程序最终都是在内存中被执行的,系统中有一个特定的程序专门负责程序的加载,这个程序被称为加载器。动态库,又叫共享库、动态链接库等。

2024-08-19 16:16:30 1615

原创 C++11工作窃取式线程池

工作窃取式线程池采用了工作窃取算法,具体来说就是当某个线程执行完自己队列中的任务后,会从其他线程的队列中“偷取”任务来执行。这种算法可以提高线程利用率,减少线程之间的竞争,以及减小线程的等待时间。在同步队列中设计std::vector<std::list<T>>,使用该容器来存储任务,利用数组加链表,设置vector的大小为bucketsize,即一般为CPU核数,利用链表存放具体任务。

2024-08-15 21:34:58 876

原创 C++11缓存式线程池

动态调整线程数量:与固定式线程池不同,缓存式线程池的线程数量是动态调整的。当有新任务提交时,如果线程池中有空闲的线程,则会立即使用空闲线程执行任务;如果线程池中没有空闲线程,则会创建一个新的线程来执行任务。当线程空闲一段时间后,超过线程最大空闲时间(默认为60s),线程将会被回收和销毁。

2024-08-14 21:34:17 633

原创 C++11固定式线程池

除了void Take(T& x)接口,每次获取到锁后,只能获取一个数据,其实这时队列中可能有多条数据,如果每条数据都加锁获取,效率是很低的,这里做出改进,做到一次加锁就能将队列中所有数据都取出来,从而大大减少加锁的次数。ThreadPool中有3个成员变量,一个是线程组,这个线程组中的线程是预先创建的,应该创建多少个线程由外面传入,一般建议创建CPU核数的线程以达到最优的效率,线程组循环从同步队列中取出任务并执行,如果线程池为空,线程组将处于等待状态,等待任务的到来。

2024-08-13 21:49:40 448

原创 线程池概述

同步服务层则会不断地将新的任务添加到同步排队中,有可能上层的任务非常多,而任务又是非常耗时的,这时,异步层中的线程处理不过来,则同步排队层中的任务会不断增加,如果同步排队层不加上限控制,则可能会导致排队层中的任务过多,内存暴涨的问题。从活动图中可以看到线程池的活动过程,一开始线程池会启动一定数量的线程,这些线程属于异步层,主要用来并行处理排队层中的任务,如果排队层中的任务数为空,则这些线程等待任务的到来,如果发现排队层中有任务了,线程池则会从等待的这些线程中唤醒一个来处理新任务。

2024-08-12 21:27:22 933

原创 设计LRU缓存结构

3. set(key, value):将记录(key, value)插入该结构,如果关键字 key 已经存在,则变更其数据值 value,如果不存在,则向缓存中插入该组 key-value ,如果key-value的数量超过capacity,弹出最久未使用的key-value。3.返回的value都以字符串形式表达,如果是set,则会输出"null"来表示(不需要用户返回,系统会自动输出),方便观察。1.某个key的set或get操作一旦发生,则认为这个key的记录成了最常使用的,然后都会刷新缓存。

2024-08-10 17:14:15 612

原创 C++11智能指针--weak_ptr

弱引用指针weak_ptr是用来监视shared_ptr的生命周期,是shared_ptr的一个助手。weak_ptr没有重载操作符*和->,因为它不与shared_ptr共享指针,不能操作资源,主要是通过shared_ptr获得资源的检测权,它的构造不会增加引用计数,它的析构也不会减少引用计数,纯粹只是作为一个旁观者来监视shared_ptr中管理的资源是否存在。weak_ptr还可以用来返回this指针和解决循环引用的问题。

2024-08-04 18:46:02 380

原创 C++11智能指针--shared_ptr

同时shared_ptr使用经典的“引用计数”方法来管理对象资源,每个shared_ptr对象关联一个共享的引用计数。(2)当任何shared_ptr对象超出作用域时,则在其析构函数中,将与资源对象关联的引用计数减1.如果引用计数变为0,则表示没有其他shared_ptr对象与此资源对象关联,在这种情况下,它使用deleter删除器删除该资源对象。(1)当新的shared_ptr对象与资源对象的地址关联时,则在其构造函数中,将与此资源对象关联的引用计数加1.(5)在容器保存shared_ptr对象是安全。

2024-08-04 16:26:12 644

原创 C++11智能指针--unique_ptr

unique_ptr在要表达“专属所有权”的语义时使用,即unique_ptr指针永远拥有其指向的对象,所以unique_ptr是一个move_only类型,一个unique_ptr指针是无法被复制的,只能将所有权在两个unique_ptr指针之间转移,转移完成后原来的unque_ptr将被设为nullptr。(1)语义简单,即当你确定要使用的指针是不是被共享所有权的时候,认选unique_ptr独占式所有权,当确定要被共享的时候可以转换成shared_ptr;

2024-08-03 22:01:29 525

原创 C++11智能指针--auto_ptr

内存泄漏是指程序中已动态分配的堆内存由于某种原因未释放或无法释放,导致程序运行速度减慢甚至系统崩溃等问题。内存泄漏分为以下两类:(1)堆内存泄露:我们经常说的内存泄漏就是堆内存泄露,在堆上申请了资源,在结束使用的时候,没有释放归还给操作系统,从而导致该块内存不会再次被使用。(2)资源泄露:通常指的是系统资源,比如socket,文件描述符等,因为这些在系统中都是有限制的,如果创建了而不归还,久而久之,就会耗尽资源,导致其他程序不可用。

2024-08-03 20:51:06 704

原创 生产者消费者模型原理以及C++实现

生产者、消费者问题也被称作有限缓冲问题。可以描述为:两个或者更多的线程共享同一个缓冲区,其中一个或多个线程作为“生产者”会不断地向缓冲区中添加数据,另一个或者多个线程作为“消费者”从缓冲区中取走数据。生产者、消费者模型关注的是以下几点:1、生产者和消费者必须互斥的使用缓冲区。2、缓冲区空时,消费者不能读取数据。3、缓冲区满时,生产者不能添加数据。

2024-08-02 20:01:28 330

原创 C++跳跃表个人理解

跳跃表是平衡树一种替代的数据结构,但是和红黑树不相同的是,跳跃表对于平衡的实现是基于一种随机化的算法,跳跃表的插入和删除工作是比较简单的。比如,给定一个长度为7的有序链表,节点值依次是1->2->3->5->6->7->8,那么我们可以取出所有值为奇数节点的作为关键点。最后回到原链表,找到并插入对应位置。确定了新节点在关键节点中的位置(3和5之间),就可以回到原链表,迅速定位到对应的位置,然后进行插入。对于跳跃表来说,当然不能只会有一层索引节点,那么可以进一步提取索引,在索引层中提取出一层新的索引。

2024-08-01 20:53:54 487

原创 进程间通信方式效率排序--个人理解

消息队列的实现会在内核中维护一个消息链表,数据的写和读都存在用户态到内核态来回的数据拷贝,由于消息的结构,消息会分为多种类型,会据此将链表划分为多个形式的链表,当消息被读取,就会从内核中将这个消息体删除。依据:共享内存允许两个或多个进程直接访问同一块物理内存区域(具体做法,将两个进程的中的虚拟地址映射到同一块物理内存空间中,存在一些系统调用可以实现),数据的读写无需内核的额外复制操作,比如用户态到内核态的切换以及数据的来回拷贝,速度相对较快。例如,进程可以将多个相关的数据组合成一个消息发送到队列中。

2024-07-31 14:20:28 359

原创 进程间通信--套接字socket

对于UDP来说,不需要维护连接,那么也就没有所谓的发送方和接收方,甚至都不存在客户端和服务端的概念,只要有一个socket多台机器就可以任意通信,因此每一个UDP的socket都需要bind。type参数用来指定通信特性,比如SOCK_STREAM表示的是字节流,对应TCP\SOCK_DGRAM表示的是数据报,对应UDP、SOCK_RAW表示的是原始套接字;前面提到的管道、消息队列、共享内存、信号和信号量都是在同一台主机上进行进程间通信,那要想跨网络与不同主机上的进程之间通信,就需要Socket通信了。

2024-07-30 20:54:55 380

原创 进程间通信--信号

当我们不希望处理某些信号的时候,就可以忽略该信号,不做任何处理。Linux对每种信号都规定了默认操作,例如上面列表中的SIGTERM信号,就是终止进程的意思。在Linux操作系统中,为了响应各种各样的事件,提供了几十种信号,分别代表着不同的意义。对于异常情况下的工作模式,就需要用信号的方式来通知进程。,因为可以在任何时候发送信号给某一进程,一旦有信号产生,我们就有下面这几种,用户进程对信号的处理方式。运行在shell终端的进程,我们可以通过键盘输入某些组合键的时候,给进程发送信号。

2024-07-30 20:30:04 372

原创 进程间通信--信号量

另外,在多进程里,每个进程并不一定是顺序执行的,它们基本是以各自独立的、不可预知的速度向前推进,但有时候我们又希望多个进程能密切合作,以实现一个共同的任务。例如,进程A是负责生产数据,而进程B是负责读取数据,这两个进程是相互合作、相互依赖的,进程A必须先生产了数据,进程B才能读取到数据,所以执行是有前后顺序的。可以发现,信号初始化为1,就代表着是互斥信号量,它可以保证共享内存在任何时刻只有一个进程在访问,这就很好的保护了共享内存。那么这时候,就可以用信号量来实现多进程同步的方式,我们可以初始化信号量为0.

2024-07-30 19:57:26 241

原创 进程间通信--共享内存

现在操作系统,对于内存管理,采用的是虚拟内存技术,也就是每个进程都有自己独立的虚拟内存空间,不同进程的虚拟内存映射到不同的物理内存中。所以,即使进程A和进程B的虚拟地址是一样的,其实访问的是不同的物理内存地址,对于数据的增删改查互不影响。消息队列的读取和写入的过程,都会有发生用户态与内核态之间的消息拷贝过程。那共享内存的方式,就很好的解决了这一问题。这样这个进程写入的东西,另外一个进程马上就能看到了,都不需要拷贝来拷贝去,传来传去,大大提高了进程间通信的速度。

2024-07-30 16:59:26 135

原创 进程间通信--消息队列

在发送数据时,会分成一个一个独立的数据单元,也就是消息体(数据块),消息体是用户自定义的数据类型,消息的发送方和接收方要约定好消息体的数据类型,所以每个消息体都是固定大小的存储块,不像管道是无格式的字节流数据。比如,A进程要给B进程发送消息,A进程把数据放在对应的消息队列后就可以正常返回了,B进程需要的时候再去读取数据就可以了。,因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。(2)附件也有大小限制。

2024-07-30 16:30:21 210

原创 进程间通信--管道

对于匿名管道也就是无名管道,它的通信范围是存在于父子关系的进程。因为管道没有实体,也就是没有管道文件,只能通过fork来复制父进程fd文件描述符,来达到通信的目的。对于命名管道也就是有名管道,它可以在不相关的进程间通信。因为有名管道,提前创建了一个类型为管道的设备文件,在进程里只要使用这个设备文件,就可以相互通信。不管是匿名管道还是命名管道,进程写入的数据都是缓存在内核中,另一个进程读取数据自然也是从内核中读取,同时通信数据都遵循先进先出原则。

2024-07-29 20:53:33 709

原创 C语言-函数指针的使用

在C语言中,函数指针是指向函数的指针变量。它可以存储函数的地址,使得可以通过该指针来调用函数。

2024-07-29 19:45:06 1485

原创 基于Linux平台日志系统详细分析

日志是指工作日志,现在的日志主要发表在网络,详细介绍一个过程和经历的记录。日志是日记的一种,是一种记录了生活和情感的写作模式,多指个人的,一般是记载每天所做的工作,就像在笔记本上写日记一样,不同的是日志是发表在网络上的虚拟空间储存,在这个基础上进一步提高了效率和节约时间,只要申请一个个人博客即可,在日志里可以记录一些琐事,写下一些心情。

2024-07-27 20:51:57 1293

原创 心跳机制详解

心跳机制出现在TCP长连接中,客户端和服务端之间定时发送一种特殊的数据包通知对方还在线,以确保TCP连接地可靠性,有可能TCP连接由于某些原因(例如网线被拔了,突然断电)导致客户端断了,但是服务端不知道客户端断了,服务器还保持与客户端连接的状态,所以为了不浪费资源需要知道客户端非正常中断,服务器应该断开客户端断开连接,需要加入心跳机制。TCP本身内置了keepalive心跳机制,但是这种内置的心跳机制不足以满足所有的情况,所一有必要自己写心跳机制。

2024-07-26 18:37:10 319

原创 小数据量排序--“插入排序”

插入排序的优点在于简单、易于实现。对于已经有序的数组来说,插入排序只需要进行比较操作而不需要进行交换操作,因此速度非常快。但是对于无序数组来说,插入排序的时间复杂度会比较高,不太适合大规模的排序。插入排序的时间复杂度是O(n^2),但是在插入小规模数据时,插入排序比较高效。并且,插入排序是一种稳定的排序算法,即排序前后,每个元素的相对位置不会发生变化。它是小数据量排序的王者。

2024-07-15 18:41:55 204

原创 个人对于“链接”的理解

链接器的输入是一组可重定位目标模块。函数和已初始化的全局变量是强符号,未初始化的全局变量是弱符号。规则1:不允许有多个同名的强符号。规则2:如果有一个强符号和多个弱符号同名,那么选择强符号。规则3:如果有多个弱符号同名,那么从选择这些弱符号中任意选择一个。

2024-07-14 21:29:00 845

原创 Json和Protobuf区别详细分析

JSON和protobuf分析:首先,Json在windows平台或者是Linux平台提供了大量的API函数,方便直接对其进行使用。protobuf是谷歌开发的一种数据传输格式,比json的数据量更小,也更对象化。protobuf不是像JSON直接明文,这个是定义对象结构,然后由protobuf库去把对象转换成二进制,用的时候再自动反解过来的。传输对于我们来说是透明的,我们只管传输的对象就可以了。

2024-06-11 22:51:53 626

原创 C++11std::bind的简单使用

std::bind用来将可调用对象与其参数一起进行绑定,绑定后的结果可以用std::function(可调用对象包装器)进行保存,并延迟调用到任何我们需要的时候。(2)将多元(参数个数为n,n>1)可调用对象转换成一元或者(n-1)元可调用对象,即只绑定部分参数。注:std::placeholders为一个占位符,代表这个位置在函数调用时,将被第几个参数所替代。(1)将可调用对象与其参数绑定成一个仿函数。

2024-05-25 13:07:42 376

原创 C++11function包装器的使用

通常std::function是一个函数对象类,它包装其它任意的函数对象,被包装的函数对象具有类型为T1,...Tn的n个参数。类模板std::function是一种通用、多态的函数包装。std::function的实例可以对任何可以调用的目标实体进行存储、std::function使用模板转换构造函数接收被包装的函数对象。C++中现有的可调用实体的一种类型安全的包裹(像函数指针这类可调用实体,是类型不安全的)(2)是一个具有operator()成员函数的类对象。(3)是一个可以被转换为函数指针的类对象。

2024-05-24 22:07:52 536

原创 三次握手、四次挥手

2023-08-14 17:52:52 114

原创 如何检测内存泄漏问题?

内存泄漏指的是程序在运行过程中动态分配的内存空间在使用完毕后没有被正确释放,从而导致这部分内存无法再被程序使用,随着程序的运行,泄露的内存会不断累积,最终可能导致系统内存耗尽。

2025-04-02 19:49:52 293

原创 使用UDP建立连接,会存在什么问题?

在网络不稳定的环境下,例如信号较弱的无线网络中,数据包丢失的概率增加,这可能导致客户端和服务端之间的数据不一致。如在线游戏中,玩家的操作指令通过UDP发送,如果部分指令丢失,可能会使游戏出现异常,影响玩家的游戏体验。在实时通信场景中,若客户端向服务端发送数据,但服务端此时不可用,数据会被丢弃,而客户端无法及时得知服务端的状态,可能会持续发送数据,造成资源浪费。这可能会进一步加重网络拥塞,导致网络性能严重下降,不仅影响UDP连接本身,还可能影响其他使用TCP协议的网络连接。

2025-04-02 19:24:36 223

原创 如何判断一条连接是TCP连接还是UDP连接?

tcpdump是命令行抓包工具,抓取的数据包信息虽不如Wireshark直观,但通过分析数据包的相关信息,也能判断连接类型。TCP是面向连接的协议,通信前会通过三次握手建立可靠连接,传输过程中有确认、重传机制,以此确保数据的可靠传输。UDP是无连接协议,不建立连接,直接发送数据,也没有确认和重传机制,数据传输不保证可靠。像HTTP协议,默认使用TCP的80端口,HTTPS使用TCP的443端口;DNS服务在进行域名解析时,查询操作通常使用UDP的53端口,而区域传输时则使用TCP的53端口。

2025-04-02 18:42:04 271

原创 select、poll、epoll的区别

select 单个进程所能打开的最大连接数由FD_SETSIZE宏定义,其大小是32个整数大小(在32位的机器上,大小就是3232,同理64位机器上FD_SETSIZE为3264),当然我们可以对进行修改,然后重新编译内核,但是性能会受到影响,这需要进一步的测试。(1024)poll 本质上和select没有区别,但是他没有最大连接数的限制,原因是它是基于链表来存储的。epoll 虽然连接数有上限,但是很大,受内存以及系统资源限制。

2025-04-01 21:35:29 853

原创 优先级队列(priority_queue)

简单理解:typename是数据的类型;container是容器类型,可以是vector,queue等用数组实现的容器,不能是list,默认用的vector;functional是比较的方式,默认是大顶堆(就是元素值越大,优先级越高);如果使用C++基本数据类型,可以直接使用自带的less和greater这两个仿函数(默认使用的是less,就是构造大顶堆,元素小于当前节点时下沉)。使用自定义的数据类型的时候,可以重写比较函数,也可以在自定义类型中进行运算符重载(less重载“<”运算符,构造大顶堆;

2025-04-01 17:10:47 125

空空如也

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

TA关注的人

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