Unix下五种IO模型
http://blog.chinaunix.net/uid-25324849-id-247813.html
1. I/O模型
Unix下共有五种I/O模型
a. 阻塞I/O
b. 非阻塞I/O
c. I/O复用(select和poll)
d. 信号驱动I/O(SIGIO)
e. 异步I/O(Posix.1的aio_系列函数)
1). 阻塞I/O模型
应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好。
如果数据没有准备好,一直等待。。。。
数据准备好了,从内核拷贝到用户空间
I/O函数返回成功指示

2). 非阻塞I/O模型
我们把一个套接口设置为非阻塞就是告诉内核,当所请求的I/O操作无法完成时,不要将进程睡眠,而是返回一个错误。这样我们的I/O操作函数将不断的测试 数据是否已经准备好,如果没有准备好,继续测试,直到数据准备好为止。在这个不断测试的过程中,会大量的占用CPU的时间。

3). I/O复用模型
I/O复用模型会用到select或者poll函数,这两个函数也会使进程阻塞,但是和阻塞I/O所不同的的,这两个函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。 
4). 信号驱动I/O模型
首先我们允许套接口进行信号驱动I/O,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。

5). 异步I/O模型
调用aio_read函数,告诉内核描述字,缓冲区指针,缓冲区大小,文件偏移以及通知的方式,然后立即返回。当内核将数据拷贝到缓冲区后,再通知应用程序。

2. 几种I/O模型的比较
前四种模型的区别是第一阶段基本相同,第二阶段基本相同,都是将数据从内核拷贝到调用者的缓冲区。而异步I/O的两个阶段都不同于前四个模型。

3. 同步I/O和异步I/O
a. 同步I/O操作引起请求进程阻塞,直到I/O操作完成。
异步I/O操作不引起请求进程阻塞。
b. 我们的前四个模型都是同步I/O,只有最后一个异步I/O模型是异步I/O。
部分内容来自:http://blog.csdn.net/sunyubo458/archive/2010/12/24/6096723.aspx
4. Select函数
a. Select函数可以指示内核等待多个事件中的任一个发生,并仅在任一个事件发生或经某个指定的时间后才返回,才唤醒进程
b. 可以调用select函数,通知内核在下列情况发生时才返回:
集合{1,4,5}中的任何描述符准备好读,或者
集合{2,7}中的任何描述符准备好写,或者
集合{1,4}中任何描述符有异常条件待处理,或者
已经经过了10.2秒
c.描述字可以不受限制与套接字,任意的描述符都可以用select来测试
d. 函数原型
int select(int maxfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct tim *timeout);
参数说明:
timeout:告诉内核等待任一描述符准备好可以花费的时间,这里会有三种情况,
第一种情况是timeout是NULL,这样将一直等待,直到某个描述符准备好;
第二种情况是timeout的值是0,那么将不等待,立即返回;
第三种情况是timeout中的秒或微秒被赋值,那么将等待指定的时间。
此外,如果进程收到一个信号,select也会被中断返回。
readfds,writefds和exceptfds指定了让内核测试读,写和异常条件所需的描述字。
maxfds:说明了被测试的描述符的个数,它的值是要被测试的最大的描述符加1.
返回值:所有描述符集的已准备好的总位数。返回时,描述符集中任何没有准备好的描述符都被清0,我们用FD_ISSET来测试是哪个描述符准备好了。因此,每次调用select时,都要重新将我们关心的描述符在描述符集中置为1.
e. fd_set说明
fd_set是一个整数数组,每个数中的每一位对应一个描述符。例如用32位表示一个整数,那么数组的第一个元素对应于描述字0~31,第二个元素对应于描述字32~63.
四个相关的宏:
FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);
f.描述符准备好读的条件:
套接口缓冲区中的数据字节大于等于套接口接收缓冲区低潮限度的当前值。套接口将不阻塞并返回一个大于0的值,就是当前准备好读的数据字节数。
套接口收到一个FIN,套接口的读操作将返回一个0.
套接口是一个监听套接口,并且以完成的连接数非0。
有一个套接口错误待处理。套接口的读操作将返回-1.
g.描述符准备好写的条件:
套接口发送缓冲区的可用空间大于等于套接口发送缓冲区低潮限度的当前值。,且或者套接口以连接,套接口不要求连接。
套接口写这一半关闭,这样将产生一个SIGPIPE错误。
有一个套接口错误待处理。
h.描述符异常的条件:
套接口存在带外数据
仍处于带外标记
i. 每个进程可以使用的最大描述符
有一个宏FD_SETSIZE定义了一个进程可以使用的最大描述符数。如果要更改这个值不仅仅要在定义的头文件中改变,还要重新编译内核。
5. 使用select函数修改前面的客户-服务器程序
在前面的客户-服务器程序中,客户端采用的是停-等这样的策略来接收来自标准输入的用户输入,这样的好处是可以一对一的完成从用户输入,然后读取从服务器 返回的字符串,这样的弊端是当程序阻塞在等待用户输入时,无法及时的处理来自服务器的FIN等这些消息。现在我们用select函数将客户端程序做一些修 改,使能避免前面提到的问题。
另外,服务器也采用select函数,从而避免产生过多的进程,使用select后可以只有一个进程就可以处理多个客户端。在服务器端建立一个整数型的数 组,用来存放已经完成的客户端连接。每次从见天套接口读到数据后,我们将新的来自客户端的连接加入到这个数组中,并且修改maxfd的值。每次从客户端套 接口读到数据后,将读到的数据重新写回到客户端套接口。
a.服务器从客户套接口读到数据后,返回值有可能为0,这说明客户端已经关闭了写这个方向的连接。在将数据写入客户端套接口后,要将连接关闭。并将客户连接从存放客户连接的数组中移除。
b.采用上面的方案,存在一个潜在的问题就是可能受到拒绝服务的攻击。一个恶意用户和服务器建立连接,发送单个字符,但是没有发送换行符或者终止,这样服 务器将阻塞在read函数中。可能的解决办法是采用非阻塞I/O或者让每个客户用单独的进程来处理或者为I/O操作设置超时。
c.客户端接收到EOF时,只能关闭写这个方向的连接,因为我们仍然希望读取来自服务器的数据。此时是不能用close来关闭连接的,而要用 shutdown来关闭。如果套接字的访问计数大于0,那么close只是将计数减1;如果套接字的访问计数等于0,close将终止套接字的两个方向, 那样我们将不能读取仍然没有从服务器发送回来的数据。
6. shutdown函数
int shutdown(int s, int how);
参数说明:
s: 代表套接字描述字
how:SHUT_RD -- 关闭套接字的读取数据方向的连接
SHUT_WR -- 关闭套接字的写入数据方向的连接
SHUT_RDWR -- 关闭套接字双向的连接
7. pselect函数
int pselect(int n, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, const struct timespec *timeout, const
sigset_t *sigmask);
a.pselect函数采用timespec结构,这个结构支持纳秒
b.sigmask是信号掩码,将禁止递交某些信号
8. poll函数
int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
a.参数说明
ufds: 是一个struct pollfd结构体的指针
nfds: 说明我们关心的描述字的个数
timeout: 超时等待的时间,单位是毫秒
b.struct pollfd结构体说明
struct pollfd {
int fd;
short events;
short revents;
};
fd: 是描述字
events: 是在描述字上关心的事件
revents: 是在描述字上返回的事件
poll函数返回后我们要测试revents中的事件是否是我们关心的。
Unix下五种IO模型的更多相关文章
- 2018.5.4 Unix的五种IO模型
阻塞非阻塞和异步同步 同步和异步关注的是消息通信机制,关注两个对象之间的调用关系. 阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态,关注单一程序. Unix的五种IO模型 以下基于Li ...
- 简述linux同步与异步、阻塞与非阻塞概念以及五种IO模型
1.概念剖析 相信很多从事linux后台开发工作的都接触过同步&异步.阻塞&非阻塞这样的概念,也相信都曾经产生过误解,比如认为同步就是阻塞.异步就是非阻塞,下面我们先剖析下这几个概念分 ...
- Linux中同步与异步、阻塞与非阻塞概念以及五种IO模型
1.概念剖析 相信很多从事linux后台开发工作的都接触过同步&异步.阻塞&非阻塞这样的概念,也相信都曾经产生过误解,比如认为同步就是阻塞.异步就是非阻塞,下面我们先剖析下这几个概念分 ...
- Linux 下的五种 IO 模型
概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的 ...
- 聊聊 Linux 中的五种 IO 模型
本文转载自: http://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666538919&idx=1&sn=6013c451 ...
- 五种IO模型
参考文档 https://www.jianshu.com/p/486b0965c296 概念说明 用户空间和内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空 ...
- 漫谈五种IO模型
阅读目录 1 基础知识回顾 2 I/O模式 3 事件驱动编程模型 网络编程里常听到阻塞IO.非阻塞IO.同步IO.异步IO等概念,搞清楚这些概念之前,还得先回顾一些基础的概念. 1 基础知识回顾 注意 ...
- Linux 中的五种 IO 模型
Linux 中的五种 IO 模型 在正式开始讲Linux IO模型前,比如:同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一 ...
- Atitit 五种IO模型attilax总结 blocking和non-blocking synchronous IO和asynchronous I
Atitit 五种IO模型attilax总结 blocking和non-blocking synchronous IO和asynchronous I 1.1. .3 进程的阻塞1 1.2. 网络 ...
随机推荐
- Linux C进程内存布局
当程序文件运行为进程时,进程在内存中获得空间.这个空间是进程自己的内存空间.每个进程空间按照如下方式分为不同区域: 进程内存空间布局图 text:代码段.存放的是程序的全部代码(指令),来源于二进制可 ...
- 源码安装zabbix
源码安装zabbix 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 欢迎加入:高级运维工程师之路 598432640 前言:参考网上多篇源码安装的连接,自己把安装过程丢在这 ...
- C#: enum
C#的枚举类型跟C++差不多,一般我们将enum设为单个状态,比如enum color_t { RED, BLACK, GREEN}, 只能选择一个 而有的时候枚举可以作为位运算来进行与或运算,比如C ...
- JavaScript中Date(日期对象),Math对象--学习笔记
Date对象 1.什么是Date对象? 日期对象可以储存任意一个日期,并且可以精确到毫秒数(1/1000 秒). 语法:var Udate=new Date(); 注:初始值为当前时间(当前电脑系统 ...
- paper 55:图像分割代码汇总
matlab 图像分割算法源码 1.图像反转 MATLAB程序实现如下:I=imread('xian.bmp');J=double(I);J=-J+(256-1); %图像反转线性变换H=uint8( ...
- MapReduce:详解Shuffle过程
Shuffle过程是MapReduce的核心,也被称为奇迹发生的地方.要想理解MapReduce, Shuffle是必须要了解的.我看过很多相关的资料,但每次看完都云里雾里的绕着,很难理清大致的逻辑, ...
- 【py分析】
pyQuery pyQuery 是 jQuery 在 python 中的实现,能够以 jQuery 的语法来操作解析 HTML 文档,十分方便.使用前需要安装,easy_install pyquery ...
- android 自定义view详解
1.自定义View前首先要了解一下View的方法,虽然有些不一定要实现. 分类 方法 描述 创建 Constructors View中有两种类型的构造方法,一种是在代码中构建View,另一种是填充布局 ...
- Headless MSBuild Support for SSDT (*.sqlproj) Projects
http://sqlproj.com/index.php/2012/03/headless-msbuild-support-for-ssdt-sqlproj-projects/ Update: bre ...
- 【转】“C语言说到底是一门以内存为中心的编程语言” —— 这种说法正确吗?
转自:http://weibo.com/1005903613/AAgqA3kb4 LAW张粑粑的微博