linux异步io驱动程序实现,linux基础——linux下五种IO模型小结(阻塞IO、非阻塞IO、IO复用、信号驱动式IO、异步IO)...

1、阻塞IO模型 (同步I/O)

阻塞IO是指进程进行IO操做的时候,由于数据没准备好或者缓冲区里没有空间而没法进行IO操做会进入睡眠,直到数据准备或者缓冲区有空间才回被唤醒的行为。阻塞IO是最通用的IO类型,全部套接字默认状况下都是阻塞的。

687d4839ef42aa71368c3f95c90e839c.png

输入操做:read、readv、recv、recvfrom和recvmsg,调用这些输入函数之一,若是缓冲区没有数据可读,该进程会投入睡眠,直到有一些数据可达才被唤醒,唤醒以后把相应数据复制到接受缓冲区或者发送错误才返回。

输出操做:write、writev、send、 sendto 和 sendmsg,调用这些输出函数之一,若是发送缓冲区里面没有空间,进程也将进入睡眠,直到有空间为止才被唤醒,唤醒以后把相应数据写到发送缓冲区才会返回,返回值将是内核可以复制到该缓冲区中的字节数。

2、非阻塞IO模型 (同步I/O)

非阻塞IO使咱们进行IO操做时,不会由于这些操做阻塞,若是这个操做不能完成,则调用后马上出错返回。

61f3c0744238cdb44227456ccb257b9f.png

把套接字设置成非阻塞的代码以下:

int set_nonblock(int fd)

{

int old_option = fcntl(fd, F_GETFL);

int new_option = old_option | O_NONBLOCK;

fcntl(fd, F_SETFL, new_option);

return old_option;

}

输入操做:若是输入操做不能被知足(对于TCP套接字即至少有一个字节的数据可读,对于UDP套接字即有一个完整的数据报可读),内核中没有给返回相应的数据,那么,调用将当即返回一个-1错误。须要数据的话,咱们必须持续的调用这个函数(也就是所谓的循环接收这种循环接收并非阻塞,从而对CPU形成极大的浪费,也就是忙等,想要等待必定的数据,可是这些数据并无到来,而且还占用着CPU,不太常用这种IO模型)。从而将内核空间的值拷贝到用户空间。一旦拷贝完成了,输入函数就能够返回了,返回的值也就不是-1了。

输出操做:对于一个非阻塞的TCP套接字,若是其发送缓冲区中根本没有空间,输出函数调用将当即返回一个-1错误。若是其发送缓冲区中还有一些空间,返回值将是内核可以复制到该缓冲区中的字节数。

3、IO复用 (同步I/O)

IO复用是一种预先告知内核的能力,使得内核一旦发现指定的描述符集合中有一个或多个触发IO条件,它就会通知进程。这个能力叫作IO复用。

a67e242d74327c51c464cf113dc6f678.png

使用IO复用模型,咱们能够调用select或者epoll,阻塞在这两个系统调用(select、epoll_wait)之上,而不是阻塞在真正的I/O系统调用调用上(须要事先把监听的套接字设置成非阻塞)。能够同时对多个读操做,多个写操做的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操做函数。

注意:

当一个服务器 在处理多个客户时,绝对不能阻塞于单个客户相关的系统函数调用。不然致使服务器端程序被挂起,不能为其它客户提供服务。解决方法以下:

(1)使用非阻塞式I/O (2)对每一个客户有单独的控制进程提供服务 (3)对每一个I/O操做设置一个超时。

4、信号驱动式IO (同步I/O)

信号驱动式IO就是指进程预先告知内核,当某个描述符上发送事件时,内核使用信号通知相关进程。信号驱动式IO并无实现真正的异步,由于通知到进程以后,依然是由进程来完成IO操做。

a3df4f385dbb80649572efb8dc7db024.png

对于TCP套接字:信号驱动式IO不适合处理TCP套接字,由于信号产生的过与频繁,在TCP中,链接请求完成、断开链接发起、断开链接完成、数据到达、数据送走。。。都会产生SIGIO。可是咱们真正只须要它在数据到达或者数据送走的时候才产生信号。

对于UDP套接字:SIGIO信号在数据报到达套接字以及套接字上发生异步错误才会发生。(UDP套接字推荐使用)。

对于一个套接字使用信号驱动式IO,要求进程执行如下三个步骤:

(1)创建SIGIO信号的信号处理函数。

(2)设置该套接字的属主,一般使用fcntl的F_SETOWN命令设置。

(3)开启该套接字的信号驱动式IO,一般使用fcntl的F_SETFL命令打开O_ASYNC标志完成。

5、异步IO

当一个异步过程调用发出后,调用者不能马上获得结果。实际处理这个调用的部件在完成后,经过状态、通知和回调来通知调用者的输入输出操做。

7d9f7e8e7aa45e663c0861eba34df0df.png

调用aio_read函数(POSIX异步IO函数一aio_或者lio_开头),给内核传递描述符、缓冲区指针、缓冲区大小(和read相同的三个参数)和文件偏移(与lseek相似),告诉内核当整个操做完成时,如何通知咱们。该系统调用马上返回,并且在等待IO完成期间,咱们的进程不被阻塞。

信号驱动式IO和异步IO的区别:

信号驱动式IO是进程事先创建SIGIO的信号处理程序(用sigaction设置IO信号的处理方式),有若是有数据到来,内核会给进程发一个信号,通知进程,进程捕获到这个信号就会去执行处理函数部分,通常在这个函数中执行IO操做(信号发生在IO以前,IO由进程完成)。

异步IO是有进程请求异步读操做,会把套接字描述符,缓冲区指针、缓冲区大小和文件偏移一块儿发给内核,若是有数据到来,内核会把数据拷到相应的位置,而后给进程发一个信号,若是数据没有来,也必须等数据来了,内核把数据拷完以后,才给进程发一个信号,由内核通知咱们IO操做什么时候完成(信号发生在IO以后,IO由内核完成)

阻塞与非阻塞的区别:

阻塞和非阻塞关注的是

进程在等待调用结果(消息、返回值)时的状态

。阻塞是指调用结果返回以前,当前进程会被挂起。调用进程只有在获得结果才会返回。非阻塞调用指不能马上获得结果,该调用不会阻塞当前进程。

同步与异步的区别:

同步与异步关注的是

进程之间的协做方式

,同步是A进程必须获得B进程通知才能去执行某件事(A执行),异步是指A进程通知B进程去执行而后马上获得返回,而后就能够去作本身的事,B完成以后会给A发一个通知(B执行)。

参考:

https://www.zhihu.com/question/19732473

http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520112163171778/

http://blog.csdn.net/jay900323/article/details/18141217/

《UNIX网络编程》

《UNIX环境高级编程》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值