linux信号捕捉io复用,linux基础——linux下五种IO模型小结(阻塞IO、非阻塞IO、IO复用、信号驱动式IO、异步IO)-Go语言中文社区...

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

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

561c37b42d6709b8d7b79c96eed5947d.png

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

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

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

非阻塞IO使我们进行IO操作时,不会因为这些操作阻塞,如果这个操作不能完成,则调用后立刻出错返回。

22fb428494966f3c197a735a155ac1ab.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错误。如果其发送缓冲区中还有一些空间,返回值将是内核能够复制到该缓冲区中的字节数。

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

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

3c01719dcb4e26fc850a9279e32514ff.png

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

注意:

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

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

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

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

4ba17f1480fe0d39d39e85e28c049731.png

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

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

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

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

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

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

五、异步IO

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

5ed871448616b11a8b9d98269facc257.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环境高级编程》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值