版权声明:本文为博主原创文章,转前请跟博主吱一声。 https://blog.csdn.net/Ga4ra/article/details/90183574
1. 阻塞IO模型
这是最简单的 I/O 模型,一般表现为进程或线程等待某个条件,如果条件不满足,则一直等下去。
直到内核完成数据报复制,应用进程才会退出阻塞状态。
这种模型耗费时间,适合低并发,时效要求不高的情况。
2. 非阻塞IO模型
我们在等待的时候,完全可以做点别的事情,并通过轮询的方式,时不时问一下内核数据准备好没。
如果某一次轮询得知数据已经准备好了,那就把数据拷贝到用户空间中。
3. 信号驱动IO模型
如果说,内核可以自动地,在复制完数据报后通知咱的应用呢?
这就是信号驱动IO。
应用进程向内核指定信号处理函数,收到信号SIGIO
后,处理函数自动执行。
那么,如何才能多处理几个io
呢?我们可以通过下一种模型,监视多个描述符。
4. IO复用模型
通过IO复用,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
select()
会监听所有注册好的IO
。
- 如果所有被监听的IO需要的数据都没有准备好时,
select()
调用进程会阻塞; - 有描述符就绪则返回就绪的描述符个数;
- 超时时间内没有描述符就绪返回 0 ;
- 执行失败返回-1 。
int select(
int maxfd,
fd_set *rdset,
fd_set *wrest,
fd_set *exset,
struct timeval *timeout);
注意,IO
复用模型并不是非阻塞的,因为没有向内核注册信号处理函数。
5. 异步IO模型
前面的4种模型,都是同步的,因为数据拷贝都是同步进行的,都通过recvfrom
操作进行数据拷贝。
对于信号驱动模型,可以认为数据准备阶段是异步的,数据拷贝操作是同步的。
要想异步进行,就必须给内核指定更多任务。
用户进程发起aio_read()
操作之后,给内核传递描述符、缓冲区指针、缓冲区大小等;内核收到aio_read
后,会立刻返回,然后内核开始等待数据准备。
数据准备好以后,直接把数据拷贝到用户空间,省去recvfrom()
,然后再通知进程本次IO
已经完成。
异步模型显然是最省事的,啥都不用管了。