阻塞型、⾮阻塞型、复⽤型、信号驱动型、异步
引用知乎 https://zhuanlan.zhihu.com/p/115912936
TCP发送数据的流程
应用A发送数据到服务器B
1、A把消息发送到A的TCP发送缓冲区
2、TCP缓冲区把消息发送出去,经过网络传递后,消息发送到B服务器的TCP接受缓冲区
3、B从TCP缓冲区读取属于自己的数据
阻塞IO
应用间发送消息是间断性的,图中TCP缓冲区还没有接收到属于B的消息时,B向TCP缓冲区发起读取申请,在内核没有
准备好之前,B会一直处于等待数据状态,一直到内核把数据准备好交给B才结束。
阻塞IO术语描述:
在应用调用recvfrom读取数据时,其系统调用直到数据到达其被复制到应用缓冲区中或者发送错误时才返回,此期间
会一直等待,进程从调用到返回这段时间内都是被阻塞的称为阻塞IO;
流程:
1、应用进程向内核发起recvfrom读取数据。
2、准备数据包(应用进程阻塞)。
3、将数据从内核复制到应用控件。
4、复制完成后,返回成功提示。
非阻塞IO
应用B发起读取数据申请时,如果你日和没有准备好会立即告诉应用B,B不会一直等待
非阻塞IO属于描述
非阻塞IO是在应用调用recvfrom读取数据时,如果该缓冲区没有数据的话,会直接返回一个EWOULDBLOCK错误,不会
让应用一直等待,在没有数据的时候会立即返回错误表示,意味着如果应用要读取数据需要不断的调用recvfrom请求,直到
读取到需要的数据。
流程:
1、应用进程向内核发起recvfrom读取数据。
2、没有数据准备好,立即返回EWOULDBLOCK错误码。
3、应用进程向内核发起recvfrom读取数据。
4、已有数据包准备好就进行以下步骤,否则返回错误码。
5、将数据从内核拷贝到用户空间。
6、完成后返回成功提示。
IO复用模型
继续用开始的例子:并发环境下,N个人向B发送消息,应用必须创建N个线程去读取数据,同时因为应用线程是不知道什
么时候会有数据读取,为了保证能及时读取到数据,这些线程必须不断的向内核发送recvfrom请求来读取数据;
这么多线程不断调用recvfrom请求数据,会导致服务器资源严重紧张甚至卡死
能不能提供一种方式,由一个线程监控多个网络请求(fd文件描述符,linux系统把所有网络请求以一个fd来标识),这样
就可以只需要一个或几个线程就能完成数据状态询问的操作,当有数据准备好之后再分配对应的线程去读取数据,这样可以
节省出大量的线程资源,这就是 IO复用模型 的思路。
IO复用模型的思路就是系统提供了一种函数可以同时监控多个fd的操作,select、poll、epoll函数,应用线程通过调用
select函数可以同时监控多个fd,select函数监控的fd中只要有任何一个数据状态准备就绪了,select函数就会返回可读
状态,这事询问线程再去通知处理数据的线程,对应线程此时再去发起recvfrom请求去读取数据。
IO复用模型术语描述:
进程通过将一个或多个fd传递给select,阻塞select操作上,select帮我们侦测多个fd是否准备就绪,当有fd准备就绪
时,select返回数据可读状态,应用程序再调用recvfrom读取数据。
信号驱动IO模型
复用IO模型解决了一个线程可以监控多个fd的问题,但是select是采用轮询的方式监控多个fd的,通过不断的轮询fd的
可读状态来知道是否有可读的数据。而无脑的轮询大部分情况下是无效的,能不能不要总是去询问数据是否准备就绪,能不
能发出请求后等数据准备好了就通知我,所以衍生了信号驱动IO模型。
信号驱动IO不是用循环请求询问的方式去监控数据就绪状态,而是在调用sigaction时候建立一个SIGIO的信号联系,当
内核数据准备好了之后再通过SIGIO信号通知线程数据准备后的可读状态,当线程收到可读状态的信号后,再向内核发起
recvfrom读取数据的请求,因为信号驱动IO的模型下应用线程在发出信号监控后即可返回,不会阻塞,所以一个应用线程
也可以同时监控多个fd
IO复用模型里面的select虽然可以监控多个fd了,但select其实现的本质上还是通过不断的LUN寻fd来监控数据状态,因为
大部分轮询请求其实是无效的,索引信号驱动IO意在通过这种建立信号关联的方式,实现发出请求后只需要等待数据就绪的
通知即可,这样避免大量无效的数据状态轮询操作。
信号驱动IO术语描述:
首先开启套接口信号驱动IO功能,并通过系统调用sigaction执行一个信号处理函数,此时请求立即返回,当数据准备就绪时
就生成对应进程的SIGIO信号,通过信号回调通知应用线程调用recvfrom来读取数据。
异步IO模型
应用向内核发送一个read请求,告诉内核它需要读取数据后立刻返回;内核收到请求后悔建立一个信号联系,当数据准备就绪,
内核会主动把数据从内核复制到用户空间,等所有操作都完成之后,内核会发起一个通知告诉应用,这种模式为 异步IO模型
异步IO的优化思路是解决了应用程序需要先后发送询问请求、发送接收数据请求两个阶段的模式,在异步IO的模式下,只需要向
内核发送一次请求就可以完成状态询问和数据拷贝的所有操作。
异步IO模型术语描述:
应用告知内核启动某个操作,并让内核在整个操作完成之后,通知应用,这种模型与信号驱动模型的主要区别在于,信号驱动
IO只是由内核通知我们可以开始下一个IO操作,而异步IO模型是由内核通知我们操作什么时候完成。
IO模型里面的同步异步
阻塞和非阻塞:阻塞就是发起读取数据请求时,当数据还没准备就绪的时候,这时请求立刻返回,还是在等待数据的就绪,
如果等待就是阻塞,不等待立即返回就是非阻塞。
同步和异步: IO模型里面如果请求方从发起请求到数据最后完成的这一段过程中都需要自己参与,称为同步请求;如果
应用发送完指令后就不再参与过程了,只需要等待最终完成结果的通知,就属于异步。
同步阻塞和同步非阻塞:它们不通的只是发起读取请求的时候一个请求阻塞,一个请求不阻塞,相同的是,它们都需要应
用自己监控整个数据完成的过程。异步非阻塞而没有异步阻塞,因为异步模型下请求指定发送完后就立刻返回了,没有后续流程
所以不会阻塞也就只有异步非阻塞了。