5种IO模型分别如下:
1、阻塞IO模型
当上层应用app1调用recv系统调用时,如果对等方没有发送数据(缓冲区没有数据),上层app1将阻塞(默认行为,被linux内核阻塞)。
当对等方发送了数据,linux内核recv端缓冲区有数据后,内核会把数据copy给用户空间。然后上层应用app1解除阻塞,执行下一步操作。
2、非阻塞IO模型
上层应用程序app2将套接字设置成非阻塞模式。
上层应用程序app2轮询调用recv函数,接收数据,若缓冲区没有数据,上层程序app2不会阻塞,recv返回值-1,错误码是EWOULDBLOCK。
上层应用程序不断轮询有没有数据到来,会造成上层应用忙等待,大量的消耗CPU时间,很少直接用,应用范围小,一般和select IO复用配合使用。
阻塞IO和非阻塞IO是两个极端,一个是没有数据就死等,另一个极端是轮询。
有没有这样一种机制去管理n个文件描述符,当文件描述符状态发生变化了,会通知应用程序呢?这就是IO复用技术,也叫作多路复用。
3、IO复用模型
上层应用程序app3调用select机制(该机制由linux内核支持,避免了app3忙等待),进行轮询文件描述符的状态变化。
当select管理的文件描述符没有数据(或者状态没有变化时),上层应用程序app3也会阻塞。
好处是select会管理多个文件描述符。
select可以看成一个管理者,用select来管理多个IO。
一旦检测到一个IO或者多个IO有我们感兴趣的事件发生,select函数将返回,返回值为检测到的事件个数,继而可以利用select相关api函数,具体操作事件。
select函数可以设置等待时间,避免了上层应用程序app3长期僵死。
和阻塞IO模型相比,select IO复用模型相当于提前阻塞了,等到有数据到来时再调用recv就不会发生阻塞。
4、信号驱动模型:
上层应用程序app4建立SIGIO信号处理程序,当缓冲区有数据到来时,内核会发送信号告诉上层应用程序app4。
上层应用程序app4接收到信号后,调用recv函数,因缓冲区有数据,recv函数一般不会阻塞。
这种模型用的也比较少,属于典型的“拉模式”,即上层应用程序app4需要调用recv函数把数据拉进来。
应用程序接收到信号有一个时间延迟,处理这个信号可能还有一个时间延迟,如果这些延迟比较长,内核空间数据有可能发生变化。存在隐患。因此,这种IO模型用的不多。
5、异步IO模型
上层应用app5调用aio_read函数,同时提交一个应用层的缓冲区buf,调用完毕后不会阻塞,上层应用程序app5可以进行其他任务。
当TCP IP协议缓冲区有数据时,linux内核主动把内核缓冲区中的数据copy到用户空间,然后再给上层应用app5发送信号,告诉app5数据有了,赶快处理吧。
这是典型的推模式。
效率最高的一种形式,上层应用app5有异步处理的能力(在linux内核的支持下,言外之意:处理其他任务的同时,也可支持IO通讯)。
上层应用app5也可以在干别的活儿的同时接收数据。与信号驱动IO模型相比,上层应用程序app5不需要调用recv函数。
这种IO模型效率非常高,是高性能、高并发服务器常用的模型。
IO复用模型和异步IO模型是两种常用的模型。
原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9410664.html