自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 IP报文发送过程和原理

在整个的大网络中,我们会发现,不同的局域网中可以有相同的IP的主机.同时我们会发现一个路由器有两个IP地址.这是因为路由器是横跨两个网段的,它可以是该局域网的一部分(网络号和局域网一致),也可以作为一台主机和外面的其他路由器共同构成一个局域网(网络号与更大的局域网一致).当分片的报文达到对端的时候,就需要进行报文的组装了.此时IP报文中的16为标识开始发挥作用,来源于同一报文的分片报文,它们的16为标识符是一样的,这样就可以进行分堆,比如这一批报文都来自一个IP报文分片产生的.

2024-12-18 17:44:33 873

原创 TCP协议

本质上是验证两者的收发能力。1.确认双方主机是否健康,只有主机健康才能传输信息。2.验证全双工,三次握手我们是能看到双方都有收发的最小次数。​第一次握手和第二次握手可以验证客户端的收发能力,因为在第二次握手时可以确定第一次握手成功,同时第二次握手时client来接收。对于server来说,第一次握手和第三次握手可以验证它的收发能力。3.还可以预防一些SYN攻击,如果是一次握手的话,就可能有被大量SYN链接请求攻击的影响,因为建立一个链接就需要消耗一些资源。

2024-12-01 22:45:31 610

原创 http(请求方法,状态码,Cookie与)

此时就可以保证浏览器中的Cookie的信息是服务端文件的session_id,所有的http请求都会有浏览器自动携带的cookie中的session_id,后续server依旧可以认识client,也是一种会话保持的功能,但是我们还有cookie文件被泄露的风险。注意:由于应用层是人要参与的,人的水平参差不齐,http的状态码很多人不清楚该如何使用,又因为浏览器的种类太多了,导致可能对状态码的支持没有那么好,类似于404的状态码对浏览器没有指导意义,浏览器只会正常显示网页。基本所有的网站都有其对应的首页。

2024-12-01 16:20:39 1129

原创 常用端口与Udp协议

udp是全双工的,即可以在sendto的同时调用recvfrom,应用层我们调用的recv,read,write,sendto等函数,与其说是收发函数不如说是拷贝函数,其实都是在缓冲区中完成拷贝。其中udp协议中的报头是定长的8个字节,16位udp长度就是整个udp的长度,两者相减就可以得到数据的大小。udp具有接收缓冲区,但是这个接收缓冲区就不能保证收到的udp报的顺序和发送udp报的顺序一致,如果缓冲区满了,再到达的udp数据就会被丢弃;面向数据报:不能够灵活的控制读写数据的次数和数量。

2024-11-30 23:04:31 1107

原创 http协议(序列化与反序列化)

我们可以将上面的代码分为三部分,分别是基本通信代码(会话层),序列化反序列化代码(表示层),约定以及业务逻辑代码(应用层)。这些在TCP/IP四层协议中统称为应用层。http协议是应用层协议,因此需要完成以上三个工作。

2024-11-20 22:55:54 651

原创 http协议(协议发送接收格式)

我们所请求的,html,css,js,视频,音频,标签等都称之为资源。其中请求方法有很多,可以是Get等,http的版本有1.1等,状态码我们比较常见的就是404,对该状态码的解释是not fount。通过观察格式,我们发现IP是以域名的方式来呈现的,比如baidu.com,并不是我们所熟悉的点分字符串的形式。它表示的是我们的搜索内容,可以看到这里的wd=C%2B%2B,%2B表示的就是一个+。http解包的方式:一行一行读取,知道读到空行,表示之前的都是报头,下面的是报文。

2024-11-17 21:45:21 872

原创 TCP实现网络通信(多进程与多线程版本)

第一个参数代表用于监听的套接字文件的文件描述符。4.获取新连接到应用层:accept(),返回值为一个新的套接字的文件描述符,参数为监听套接字的文件描述符。1.创建网络套接字:socket(),协议族为AF_INET,套接字类型为SOCK_STREAM。1.创建网络套接字:socket(),协议族为AF_INET,套接字类型为SOCK_STREAM。第一个参数代表用于监听的套接字文件的文件描述符。3.监听网络连接:listen(),参数为套接字的文件描述符。返回的套接字文件主要负责信息的传输。

2024-11-17 20:26:38 1148

原创 网络通信过程的解析

数据链路层:负责设备之间的数据帧的传送和识别,例如网卡设备的驱动,帧同步(就是说从网线上检测到什么信号作为新帧的开始)、冲突检测(如果检测到冲突就自动重发),数据差错校验工作等。它的作用是将主机链接起来。这个地址与网络无关,也即无论将带有这个地址的硬件(如集线器、网卡、路由器等)接入到网络的何处,它都有相同的MAC地址,是不可变的。网络层:负责地址管理和路由选择,例如再IP协议中,通过IP地址来是被一台主机,并通过路由表的方式规划出两台主机之间的数据传输的线路(路由),路由器工作再网络层。

2024-11-16 20:17:03 937

原创 Linux多线程(线程池与单例模式)

有一个生产任务的线程将任务传入任务队列中,线程池中的线程从任务队列中拿到任务,并进行处理。当一个线程进入GetInstance函数时,要创建变量,但是被切走了,此时其他线程进入,就会导致线程安全的问题,因此需要进行加锁的操作。单例模式即只让对象在内存中存在一份,即一个类之定义一个对象,对于线程池来说只有一个线程池就够了。因此线程池的定义可以使用单例模式。首先我们需要定义一个静态的线程池变量以及静态的线程池方法,我们使用懒汉模式来实现。因此我们可以类比处线程池的概念,即提前创建一批线程,以便于随时处理任务。

2024-11-15 16:54:25 661

原创 Linux多线程(信号量与环形队列)

当生产者和消费者指向同一个位置的时候,队列可能为空也可能为满,因此当队列不为空,不为满的时候生产者和消费者指向的不是同一个位置。使用信号量和环形队列的好处在于,可以让消费者和生产者可以不同时访问同一块临界资源,因此不需要加锁。2.可以定义一个计数器,每放一次就++,每拿一次就--,根据计数器的值来判断队列是否已满。当队列为空时,生产者执行,队列未满时,消费者执行,这也体现了局部上的同步特性。生产者关心的是环形队列中空的位置,消费者关心的是环形队列总的数据。即销毁信号量,参数为要销毁的信号量。

2024-11-15 08:58:42 932

原创 Linux多线程(线程同步与条件变量)

生产者和消费者两个线程并行执行,当消费者要消费数据的时候要访问临界资源,需要先加锁,在访问临界资源时,发现目前还没有数据,此时在full的条件下等待。pthread_cond_wait是线程等待函数,它的第一个参数是一个条件变量类型,类型为pthread_cond_t.它的第二个参数是一个锁的类型。此时五个线程都在条件变量cond处等待,当master线程调用pthread_cond_signal信号,唤醒在cond处挂起等待的一个线程的时候,该线程开始执行,由于是while循环,因此再挂起等待。

2024-11-12 21:43:21 597

原创 Linux多线程(线程互斥与线程锁)

它的寄存器al的数据现在是0,执行交换操作,将内存中mutex的值交换个A的寄存器al中,此时线程A的al值为1,内存中mutex的置为0。当线程A被切换走时(是带着上下文数据1一起被切走的),线程B到来,它的al寄存器中的值为0(线程设置的是自己的上下文数据,互相不冲突),进行交换mutex的值和al寄存器的值(0和0交换),最终B拿到的值是0,发生挂起等待。过了一会,A线程带着它的临时数据1000回来了,它认为tickets的值还是原来的1000,执行减减操作,将值变成了999,此时写回了内存中。

2024-11-11 19:32:43 700

原创 Linux多线程(线程的创建,等待,终止,分离)

在OS书籍中,线程的概念通常是这样的:线程是在进程内部运行的一个执行分支(执行流),属于进程的一部分,粒度比进程更加细,更加轻量化。通过这段话我们知道,线程与进程的比是n:1的,在其他的操作系统中,由于线程的数量较多,OS需要对线程管理起来,就会存在先描述,后组织这一方式来管理线程。但是在Linux系统下,并不是这样管理线程的。

2024-11-08 21:38:17 642

原创 C++静态成员函数

静态成员属于类但不属于对象,静态成员变量在类内声明类外定义,变量在类外分配空间。

2024-11-08 17:15:40 739

原创 C++特殊类的设计

开头整体说明一下,要求特殊类不能实现的功能,一种方式是将这种方式私有化,另一种方式是用特殊的关键字控制。

2024-11-06 21:13:07 430

原创 优先级队列

首先要注意的就是别与队列(queue)搞混了,队列是一种先进先出(First in First out,FIFO)的数据类型。每次元素的入队都只能添加到队列尾部,出队时从队列头部开始出。优先级队列(priority_queue)其实,不满足先进先出的条件,更像是数据类型中的“堆”。优先级队列每次出队的元素是队列中优先级最高的那个元素,而不是队首的元素。这个优先级可以通过元素的大小等进行定义。比如定义元素越大优先级越高,那么每次出队,都是将当前队列中最大的那个元素出队。typename是数据的类型;

2024-11-04 22:36:09 920

原创 Linux进程信号的处理

信号的内容有很多,总结起来可以分为三个大方向:信号产生前,信号产生中,信号产生后。信号的产生共有四种方式,分别是由键盘产生,进程崩溃产生,系统调用产生,和软件条件产生。信号产生中要记住三张表以及它们代表的含义。以及处理三张表的各种接口。信号产生后需要了解用户态和内核态,以及进程对信号的检测和处理的"合适时间"所指。以及两个可以修改信号的函数。最后补充了三个概念,分别是可重入函数,volatile关键字以及SIGCHLD信号。

2024-10-29 19:53:22 938

原创 进程通信(SystemV通信方式:共享内存,消息队列,信号量)

1.没有调用read/write等系统调用接口,所以共享内存一旦被创建就会映射到自己进程地址空间,shmat的使用方法就如同malloc的使用方法。不需要任何系统调用接口。2.当client没有启动或者没有进行写入,或者已经写入结束的时候,server还是对共享内存的内容进行读取,读取和写入两者之间并互不相干扰,所以共享内存也是进程通信的方式中最快的。3.共享内存不提供任何同步或者互斥的机制,而是需要程序员自行保证数据的安全。本节主要学习了SystemV的三种通信方式,其中重点学习了共享内存。

2024-10-21 10:27:57 864

原创 C++回调函数

主要看最后一行,通过std::bind函数绑定了对象与对应的函数,这种方式比上面的通过类的成员函数进行回调更为简单方便。这个bind函数中的重载通常第一个是函数的指针,第二个是调用对象的指针,后面跟占位符。特别注意的是,因为函数名本身就可以表示该函数地址(指针),因此在获取函数指针时,可以直接使用函数名,也可以去函数的地址。前面函数指针的方式作为回调函数的一种方式,可以同时用于C和C++,下面介绍另外的一些方式,因为C++引入了对象的概念,可以使用类的成员和静态函数作为回调函数。下面看一个具体的例子。

2024-10-17 11:51:59 504 1

原创 网络套接字(Udp实现简单的网络通信)

对于服务器来说,如果绑定的是确定的IP,那么只有发出向该IP的数据才会被交给网络进程,但是一般服务器可能由许多张网卡,配置了多个IP,我们需要的不是发给某个IP的数据,而是发给所有IP的数据,因此在绑定服务器IP的时候,通常使用INADDR_ANY。第一个参数表示套接字的文件描述符,第二个参数表示缓冲区的大小,第三个参数表示方式,第四个参数表示向谁发送数据,第五个参数表示发送数据的长度。同时还要考虑大小端。第一个参数表示套接字的文件描述符,第二个参数表示缓冲区的大小,第三个参数表示读的方式,通常默认为0。

2024-10-12 22:11:01 861

原创 哈希(无序容器,哈希表)

最好的查询时,进行很少次数的比较可以找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树的结构的关联式容器使用的方式类似,只是其底层的结构不同,本文中只对unordered_map和unordered_set进行介绍,unordered_map和unordered_set可以查看文档介绍,与mutimap和mutiset是一样的。a是散列表装满程度的标志因子。插入的节点是一个pair类型,它的函数与map几乎是一模一样的,unordered的意思是混序的。

2024-10-02 22:56:25 1018

原创 C++IO流

ofs<<info._ip返回的是ostream&类型,而不是ifstream&类型,我们重载的是ifstream&类型,因此不能继续打印info._d。要想继续打印,需要将重载函数的ifstream&类型转换为ostream类型&。这也就是为什么cout可以同时处理多个对象的原因,例如:cout<<a<<b,cout<<a返回的是一个cout,然后再继续cout<<b。我们发现ifstream压根就没有对ostream中的<<的重载进行重写(没有必要),使用的依然是ostream这个类中的<<。

2024-09-27 19:50:20 1142

原创 【C++11新特性】多线程

主要通过RAII的方式,对其管理的互斥量进行了封装,在需要加锁的地方,只需要用上述介绍的任意互斥体实例化一个lock_guard,调用构造函数成功上锁,出作用域前,lock_guard对象要被销毁,调用析构函数自动解锁,可以有效避免死锁的问题。在这段代码中,t1和t2两个线程对同一个信号量进行++操作,由于底层的++操作不是原子的,可能会导致x的数值混乱,因为对于一个++操作来说,它底层的汇编大概会分为三步,分别是ld,++,sd。但如果加在里面虽然是并行运行,这样频繁的加锁解锁是需要消耗资源的。

2024-09-24 10:54:18 961

原创 【C++11】异常处理

1.异常规格说明的目的是让函数使用者知道,可以在函数的后面接throw类(类型),列出这个函数可能抛出的所有异常。2.函数后面接throw(),表示函数不抛异常。3.若无异常接口声明,则此函数可以抛掷任何类型的异常。//只会抛A/B/C/D中的某中类型的异常//这里表示这个函数只会抛出bad_alloc这种异常这个函数不会抛异常在C++中,引入了noexception//表示如果x>y不发生异常,则Compare函数不会发生异常。

2024-09-22 19:55:54 1283

原创 【C++11新特性】类的新功能,可变模板参数,包装器

expand函数中的逗号表达式:(printarg(args), 0),也是按照这个执行顺序,先执行printarg(args),再得到逗号表达式的结果0。由于是逗号表达式,在创建数组的过程中会先执行逗号表达式前面的部分printarg(args)打印出参数,也就是说在构造int数组的过程中就将参数包展开了,这个数组的目的纯粹是为了在数组构造的过程展开参数包。看这样一段代码,有一个模板函数,当同时向它的F传入函数,仿函数,以及lambda表达式的时候会实例化三个模板。这就需要对参数包进行解析。

2024-09-19 21:25:43 786

原创 【C++11】统一列表初始化,声明,新增容器,lambda表达式

C++11更像是一种从C++98/03中孕育出来的一种新的语言,C++11能更好的用于系统开发和库开发,语法更加泛化和简单化,更稳定安全,不仅功能强大,而且能提高程序员的开发效率。int _x;int _y;printf("调用了构造函数\n");//当没有构造函数时会兼容C语言的特性,当有构造函数时会调用构造函数。

2024-09-19 15:55:20 894

原创 【C++11】右值引用,完美转发

默认生成的移动赋值重载函数,对内置类型直接进行赋值,对自定义类型,如果由对应的移动赋值重载函数就调用其对应的移动赋值重载函数,如果没有则直接调用拷贝赋值。默认生成的移动构造函数,对内置类型进行值拷贝,对自定义类型,如果由对应的移动构造函数就调用其对应的移动构造函数,如果没有那么调用拷贝构造。通过观察打印结果可以发现,显然移动构造没有再开辟空间,而是直接将数据进行转移,节省了空间,由临时变量进行拷贝构造给ret还会创建一个新的对象,消耗空间。左值引用不能给右值取别名,右值引用也不能给左值取别名。

2024-09-18 22:25:21 827

原创 进程间的通信(管道通信)

进程之间的通信必要的前提是两个进程需要看到同一块资源,并且这块资源不属于任何一个进程而是由操作系统来提供的。当使用管道来进行通信的时候,这块资源表现为一个文件,可以是匿名文件(匿名管道通信),也可以是命名文件(命名管道通信),该文件的特点是在其中的数据不会被刷新到磁盘上。

2024-08-26 20:30:15 1349 1

原创 动态库和静态库(.so/dll,.a/lib)

本文主要讲了关于动静态库的两部分内容,即动静态库的使用与制作。对于动静态库的使用指的是拿到别人写好的动静态库如何加入到自己的项目中来。关于动静态库的制作分为三个步骤:首先将自己所有的源文件编译成.o文件,然后将所有的.o文件进行打包,静态库使用ar -rc来进行打包,动态库使用gcc shared来进行打包。最后将.a和.so文件和头文件包含在一起最后形成一个完整的动静态库。

2024-08-26 08:53:28 693

原创 文件操作的底层原理(inode与软硬链接,文件的时间属性)

建立文件,首先操作系统在InodeBitmap和BlockBitmap分别找到不为1的数字,将其下标作为该文件的Inode和block的编号。并将之置为1,其中Inode只有一个,block可以有多个。

2024-08-25 20:15:40 617

原创 文件操作的底层原理(文件描述符和缓冲区)

我们对文件进行操作就需要打开文件,而打开文件是由某一个进程来完成的,打开文件的本质是将文件信息加载到内存中,而一个进程可以打开很多个文件,如果有很多进程,那么内存中就存在很多的已经打开的文件的信息。此时我们将stdin的文件关闭,打开了一个新文件log.txt,它的文件描述符按顺序被设置为0,fgets函数看似是将stdin的内容拿过去,实际上默认将文件描述符为0的文件内容拿到了line中,最终打印的内容就是log.txt 的内容。用户缓冲区的数据最终刷新到系统中,系统缓冲区的数据最终刷新到硬件上。

2024-08-25 16:03:10 793

原创 Linux进程替换

进程运行起来时,它的代码和数据是要被加载到内存中的,是通过exec系列的函数来完成加载的。exec系列函数一共有七个,我们可以通过man手册来进行查询:通过观察这几个函数我们发现它们都是在exec后面加入了几种后缀名。可以通过后缀名的含义来进行区分记忆。l:表示参数采用列表(以列表的方式一个一个传入进去)。v:参数用数组。p:有p自动搜索环境变量PATH(只要说名字就可以了,不用指明路径)。e(env):表示自己维护的环境变量。(不用默认的环境变量)。

2024-08-18 07:13:56 906

原创 Linux系统进程退出与等待

这段代码的目的是:先让子进程运行5s,父进程休眠10s,这就导致了子进程在前5s是运行态,在后5s是僵尸状态(父进程在休眠,无法进行资源的回收)。首先我们要明确,status是反映子进程退出时的状态的,而进程退出有三种情况:正常退出,结果正确;C语言提供了退出码与退出原因对应函数:sterror(i),其中i表示退出码,sterror返回的是i所对应的错误的字符串。注意,我们研究的退出码的范围是第一种和第二种情况,即程序进行正常的退出,当程序由于崩溃而退出时,退出码没有意义。来获得各个进程的退出码。

2024-08-17 16:06:29 937

原创 Linux进程管理---进程地址空间

上文中提到了,页表中除了会有虚拟内存和物理内存的对应关系,还会有权限管理,当我们写C语言程序的时候,定义的字符串常量是只读的,当我们要对其进行写操作的时候会发生报错。我们知道在进程创建出来的时候,页表也会随之被创建,每一个虚拟地址对应的内存空间是限定死的,所以无论怎么对虚拟内存进行操作,它也不会更改其他进程的代码和数据。我们惊奇地发现,在没修改g_val的值之前,代码一切正常,但是修改之后g_val的地址是没有变化的,但是它的值在两个进程中却是不一样的。有人会说了,直接让进程对物理内存进行操作不香吗?

2024-08-16 17:39:24 694

原创 Linux进程管理---进程优先级,环境变量与命令行参数

环境变量一般是指操作系统中用来指定操作系统运行环境的一些参数,比如,我们在编写C程序的时候,在链接时,从来不知道我们的所了解的动静态库在哪里,但是仍然可以连接成功,生成可执行程序,原因就是相关环境变量帮助编译器进行查找。这是因为优先级是一个相对的概念,操作系统设定优先级的目的是让进程合理的享受到CPU的资源,如果将进程优先级设得过小或过大,就会出现又进程无法享受到CPU资源的问题,造成“进程饥饿”。当我们使用不同的用户登录系统时,会发现我们的初始目录是该用户的根目录,这是因为HOME环境变量来决定的。

2024-08-16 15:38:54 942

原创 C++手撕红黑树

红黑树的表意就是一颗每个节点带有颜色的二叉搜索树,并通过对节点颜色的控制,使该二叉搜索树达到尽量平衡的状态。红黑树确保没有一条路径比其他路径长两倍。和AVL树不同的是,AVL树是一棵平衡树,而红黑树可能平衡也可能不平衡(因为是尽量平衡的状态)每一次插入都对根节点置为黑操作,因为第一种情况可能导致根节点不是黑。同时对根节点置黑也并不违反三条规定。

2024-08-15 11:34:12 732

原创 STL详解---set和map

注意set只有增删查,没有修改的函数。这是因为一旦修改了key的值,set就不是一棵搜索二叉树了。set底层的普通迭代器的实现和const迭代器的实现是一样的。*pos是一个常量。此时会发生报错。

2024-08-14 14:41:05 639

原创 手撕AVL树

在AVL树中,除了需要定义平衡因子bf之外,还需要定义指向节点父节点的指针。方便我们来进行平衡因子的更新。int _bf;,_kv(kv),_bf(0){}同时和map一样,我们使用pair类型来进行数据的存储。

2024-08-13 20:47:46 705

原创 Linux进程管理---进程的状态(R,S,D,T,t,X,Z)

因此进程还需要等待,此时操作系统发现这个进程在等待,如果将其干掉,显然是不合适的,因为,磁盘需要将读写成功与否的信息返回给该进程。运行后我们发现处于S+状态,这是因为printf是对外设--显示器进行打印的,而显示器比较慢,等待其就绪是需要时间的,因此test大部分时间处于S+状态,只有少部分时间处于R状态。千万不要以为进程只会等待CPU的资源,进程有可能因为运行需要,可能会在不同的队列中,在不同的队列所处的状态是不同的。CPU在处理run_queue的时候,所有在排队的进程,都处于R状态的。

2024-08-11 21:52:04 1392

原创 Linux进程管理--用代码创建进程(fork函数)

通过观察进程编码,我们可以知道下面一个是子进程,上面的是父进程,因为子进程的ppid就是父进程的pid。当父进程有一个数据是100的时候,子进程希望重写这个数据为50,此时操作系统回为其重新开辟一段空间是父进程用原空间100,子进程使用新空间50,通过刚才的man手册,我们知道了fork创建进程的返回值pid_t类型,我们可以暂时理解成int,那么它的值有什么意义呢?当id为0时,表示为子进程,当id>0时,表示父进程,并执行相应的条件语句。注意,子进程的其他数据内容使用的还是和父进程一样的空间。

2024-08-09 20:18:07 508

空空如也

空空如也

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

TA关注的人

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