# LinuxServerProject **Repository Path**: kriko/linux-server-project ## Basic Information - **Project Name**: LinuxServerProject - **Description**: 练习使用Linux Socket - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-09-10 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Linux_Server 学习 ## 知识点总结 ### 一、关于同步,异步,阻塞,非阻塞 1. 同步和异步 同步就是每一步操作都需要知道自己依赖的操作的完成状态,他是一种可靠的任务任务序列。 异步就是仅告知任务何时开始,只需要告知任务的工作,是一种不可靠的任务序列。实现异步通知可以使用状态,通知和回调来完成,但是状态一般需要系统对某个事件进行轮询,会降低执行效率。 从消息通知的角度来看,同步操作需要知道他所依赖任务的完成状态,所以需要等待依赖任务执行完毕;异步操作的调用者不能立即得到返回状态。 简单的来说,同步就是一直等待他所依赖的任务完成,异步就是在一开始注册一个操作,在某些任务需要这个操作时,通知该事件执行。 2. 阻塞和非阻塞 阻塞和非阻塞的区别主要是从线程等待消息方面来表现,对于阻塞操作,当前线程将被挂起,无法执行其他业务。阻塞与同步的区别是,同步只是任务等待依赖的任务完成,此时线程是出于运行状态,但阻塞时,线程会被挂起,等待事件完成。 同步阻塞: 线程等待函数返回,并且没有执行其他操作,(例如read,write函数),位于挂起状态,则被称为同步阻塞。 同步非阻塞: 线程等待函数返回,并且在执行其他操作,称为同步非阻塞。 记住: 阻塞是当前线程无法执行其他操作,只能等待这个任务完成。非阻塞则可以去做其他事,但是需要系统不断轮询是否完成非阻塞操作。 ### 二、Linux五种IO模型 1. 同步阻塞IO 位于同步阻塞IO操作时,CPU将不会进行任何操作,直到所有的IO操作完成,因此不会消费CPU。 这里存在俩种状态: > 1. 等待数据准备好,在网络模型中就是等待数据传输完毕. > 2. 将内核缓冲区的数据拷贝到用户空间 在同步阻塞IO中这两步操作都是被blocking的 2. 同步非阻塞IO 非阻塞将大的整片时间的阻塞分成N多的小的阻塞, 所以进程不断地有机会 '被' CPU光顾。 这就意味着CPU必须不断询问数据是否准备好,如果数据没有准备好,那么IO操作将会返回`EAGAIN `或者`EWOULDBLOCK`的错误。 但是由于CPU只需要在小阻塞的时候执行IO操作,所以CPU将有机会执行其他的操作。 在同步非阻塞状态下,内核缓冲区拷贝到用户空间的操作是被阻塞的。 3. IO多路复用 所谓IO多路复用就是将IO操作放置到一起,用一个集合去管理,当监听到存在任何已经完成的非阻塞操作,那么就交由用户处理。 相当于IO多路复用会监听所有的IO状态,当某个IO出现了就绪状态,那么就可以调用IO操作对当前已经准备好的IO进行读写操作,不需要IO操作函数进行阻塞。 但是相比于普通的IO调用,多路复用将会产生两次系统调用。 一般在使用IO多路复用时,都会将socket设置为no-blocking,但是需要注意到系统只会在epoll/poll/select的操作上阻塞。 需要注意到,将内核缓冲区的数据复制到用户空间的操作是被阻塞的。 > 从整个IO过程来看,他们都是顺序执行的,因此可以归为同步模型(synchronous)。都是进程主动等待且向内核检查状态。 4. 信号驱动IO 注册一个信号函数,等待IO数据准备好之后系统将会发送一个信号,由信号接收函数接收,并在信号函数中处理数据。 5. 异步非阻塞IO 从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal或执行一个基于线程的回调函数来完成这次 IO 处理过程,告诉它read操作完成了。 > 如果这个进程正在用户态忙着做别的事(例如在计算两个矩阵的乘积),那就强行打断之,调用事先注册的信号处理函数,这个函数可以决定何时以及如何处理这个异步任务。由于信号处理函数是突然闯进来的,因此跟中断处理程序一样,有很多事情是不能做的,因此保险起见,一般是把事件 “登记” 一下放进队列,然后返回该进程原来在做的事。 > > 如果这个进程正在内核态忙着做别的事,例如以同步阻塞方式读写磁盘,那就只好把这个通知挂起来了,等到内核态的事情忙完了,快要回到用户态的时候,再触发信号通知。 > > 如果这个进程现在被挂起了,例如无事可做 sleep 了,那就把这个进程唤醒,下次有 CPU 空闲的时候,就会调度到这个进程,触发信号通知。 6. 异步阻塞 相当于注册一个通知事件,表示当事件完成之后,系统将会通知任务完成,但是系统却被阻塞等待这个通知发生。