一、 首先明确,IO多路转换是用来干啥滴:IO多路转换多用于一个进程有多个输入多个输出的情况。
二、 其次要明白, 对于多路对于多个输入多个输出的情况,可以用多种方法:①直接一个进程用阻塞IO②分成多个进程分别进行IO读写③一个进程中用多个线程进行④用异步IO
三、 然后就是说明,IO多路转换相对于其他方法的优点了。首先说说其他方法的缺点:
①对于直接用一个进程进行阻塞IO,显然的任何一个IO读写阻塞,进程将无法进行下去,效率低啊。
②对于多个进程分别进行IO,有个问题就是:对于各个进程啥时候结束的操作很麻烦。
③对于一个进程中多个线程的情况:要线程间的同步,也很麻烦
④对于异步IO ,有些系统不支持呐,还有个问题就是往往是发生信号,进行信号处理的,确定是哪个IO发出的信号是个麻烦事。
四、 重点说说异步IO
1.异步IO的原理就是:通过某些函数,读取自己感兴趣的IO口的"状态",“等到”如果相关IO状态准备好了,比如说某一个IO口可以读了,那么这个函数就返回,告诉系统哪个IO口可以进行读操作了。注意“等到”这个词的理解,这些函数往往是对等待有时间限制的。当然也可以无限等待,根据函数的自己传入的参数而定。"状态”这个词是指:有数据可读?可对文件写了?异常?
2.相关的函数:select,pselect,poll
int select(int maxfdp1,fd_set *restrict readfds,fd_set *restrict writefds,fd_set *restrict exceptfds,struct timeval *restrict tvptr)
int pselect(int maxfdp1,fd_set *restrict readfds,fd_set *restrict writefds,fd_set *restrict exceptfds,const struct timespec *restrct tvptr,const sigset_t *sigmask)
int poll(struct pollfd fdarray[],nfds_t nfds,int timeout)
这三个函数的共同点就是:①哪些IO口也就是哪些文件描述符感兴趣,②其次这些文件描述符的什么状态感兴趣,最后返回有时间限定。
select 和pselect函数对以①②两个问题的解决方案是:用数据结构fd_set即文件描述符集合来表述,这个数据结构中每一位描述一个文件描述符,如果此位为1,表述对该文件描述符感兴趣。读的状态的一个集合,写的状态的一个集合,异常状态的一个集合。比如读的集合中fd=5这位为1,表述对fd=5的对应的文件的读状态感兴趣。
对于③,用了数据结构struct timeval {
long tv_sec;
long tv_msec;
};
tvptr=NULL时表示无限等待,tvptr=0时表示不等待直接返回,tvptr等于其他值时,表示最多等待这么多时间。
而poll函数为了解决①②这个问题则是另外一种表述方式。他将文件描述符作为分类方式,即建立这么个结构
struct pollfd {
int fd;/*刚兴趣的文件描述符,用户设定*/
short events; /*用户对文件描述符的哪些状态感兴趣,用户设定*/
short revents;/*感兴趣中的这些状态中哪些已经发生了,系统自动设定*/
};
对于③,用了int timeout表示,其单位是秒s。
time=-1,无限等待;time=0不等待;time>0等待的秒数。
注:events可以设定的值:POLLIN,POLLRDNORM,POLLRDBAND,POLLPRI,POLLOUT,POLLWANORM,POLLWRBAND
revents可能的值:POLLIN,POLLRDNORM,POLLRDBAND,POLLPRI,POLLOUT,POLLWANORM,POLLWRBAND,POLLERR,POLLHUP,POLLNVAL.
最后要说明的是:这三个函数有三种情况导致其返回:①刚兴趣的状态出现②时间到③被信号中断。
pselect 多了一个 sigset_t sigmask 即多了信号屏蔽位,对这些信号进行屏蔽。