《unix高级环境编程》高级 I/O—— I/O 多路转接
来源:互联网 发布:谜一样的双眼知乎 编辑:程序博客网 时间:2024/06/08 03:17
当我们想要多次对描述符进行 read 时,多路转接技术能够满足该要求。I/O 多路转接技术首先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已准备好进行 I/O 时,该函数才返回,返回时,告诉进程哪些描述符已经准备好可以进程 I/O 操作。
select 和 pselect 函数
- /* IO多路转接*/
- /*
- * 函数功能:
- * 返回值:准备就绪的描述符数,若超时则返回0,出错则返回-1;
- * 函数原型:
- */
- #include <sys/select.h>
- int select(int maxfdpl, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *tvptr);
- /*
- * 说明:
- * 参数maxfdpl是“最大描述符加1”;
- * 参数readfds、writefds、exceptfds是指向描述符集的指针,即描述符可读、可写或处于异常条件的;
- * 时间参数有三种取值:
- * tvptr == NULL;
- * 永远等待;若捕获到信号则中断此无限期等待;当所指定的描述符中的一个已准备好或捕获到信号则返回;
- * 若捕获到信号,则select返回-1,errno设置为EINTR;
- *
- * tvptr->tv_sec == 0 && tvptr->tv_usec == 0;
- * 完全不等待;测试所有描述符并立即返回,这是得到多个描述符的状态而不阻塞select函数的轮回方法;
- *
- * tvptr->sec != 0 || tvptr->usec != 0;
- * 等待指定的秒数和微妙数;当指定的描述符已准备好,或超过指定的时间立即返回;
- * 若超过指定的时间还没有描述符准备好,则返回0;
- *
- * tvptr的结构如下:
- */
- struct timeval
- {
- long tv_sec; /* seconds */
- long tv_usec; /* and microseconds */
- };
- #include <sys/select.h>
- int FD_ISSET(int fd, fd_set *fdset); //测试描述符fd是否在描述符集中设置;若fd在描述符集中则返回非0值,否则返回0
- void FD_CLR(int fd, fd_set *fdset); //清除在fdset中指定的位fd;
- void FD_SET(int fd, fd_set *fdset); //设置fd在fdset中指定的位;
- void FD_ZERO(fd_set *fdset); //清除整个fdset;即所有描述符位都为0;
声明了一个描述符集后,必须使用 FD_ZERO 清空其所有位达到初始化,然后才可以设置各个位;从 select 返回时,使用 FD_ISSET 测试该集中的一个给定位是否仍旧设置;
select 函数有三个可能的返回值:
- 返回值-1表示出错。这种情况下,将不修改其中任何描述符集。
- 返回值0表示没有描述符准备好。若指定的描述符都没有准备好,而且指定的时间已经超过,则发生这种情况。此时描述符集都被清0.
- 正返回值表示已经准备好的描述符数,该值是三个描述符集中已准备好的描述符之和。三个描述符集中仍旧打开的位对应与已准备好的描述符。
- 若对读集 readfds 中的一个描述符的 read 操作将不会阻塞,则此描述符是准备好的。
- 若对写集 writefds 中的一个描述符的 write 操作将不会阻塞,则此描述符是准备好的。
- 若异常状态集 exceptfds 中的一个描述符有一个未决异常状态,则此描述符时准备好的。
- 对于读、写和异常状态,普通文件描述符总是返回准备好的。
- /*
- * 函数功能:获取准备好的描述符数;
- * 返回值:准备就绪的描述符数,若超时则返回0,出错则返回-1;
- * 函数原型:
- */
- #include <sys/select.h>
- int pselect(int maxfdpl, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *tsptr,
- const sigset_t *sigmask);
pselect与select有以下几个不同:
- select 的超时用 timeval 结构指定,pselect 使用 timespec 结构。
- pselect 的超时值被申明为 const,这保证了调用 pselect 不会改变此值。
- 对于 pselect 可使用一个可选择的信号屏蔽字。若 sigmask 为空,那么在于信号有关的方面,pselect 的运行状况和 select 相同。否则,sigmask指向一个信号屏蔽字,在调用pselect时,以原子操作的方式安装该信号屏蔽字,在返回时回复以前的信号屏蔽字。
poll 函数
该函数与 select 函数类似,只是程序员接口不同。该函数不是为每个状态构造描述符集,而是构造一个 pollfd 结构数组,每个数组元素指定一个描述符编号以及对其所关心的状态。
- /*
- * 函数功能:和select函数类似;
- * 函数原型:
- */
- #include <poll.h>
- int poll(struct pollfd fdarray[], nfds_t nfds, int timeout);
- /*
- * 说明:
- * timeout == -1; 永远等待。
- * timeout == 0; 不等待,测试所有的描述符并立即返回。
- * timeout > 0; 等待timeout毫秒,当指定的描述符之一已经准备好,或指定的时间值已经超过时立即返回。
- */
pollfd 结构数组如下:
- struct pollfd{
- int fd; /* file descriptor to check,or <0 to ignore */
- short events; /* events of interest on fd */
- short revents; /* events that occurred on fd */
- };
测试程序:
- #include "apue.h"
- #include <sys/select.h>
- #include <sys/types.h>
- int main(void)
- {
- char rbuf[1024];
- fd_set rd_fds;
- int ret,len;
- struct timeval tv;
- for(; ;)
- {
- FD_ZERO(&rd_fds);
- FD_SET(STDIN_FILENO,&rd_fds);
- tv.tv_sec = 5;
- tv.tv_usec = 0;
- ret = select(1,&rd_fds,NULL,NULL,&tv);
- if(ret < 0)
- {
- err_sys("select error");
- break;
- }
- else if(ret == 0)
- printf("timeout,waiting next loop\n");
- else
- {
- printf("ret = %d\n",ret);
- if(FD_ISSET(STDIN_FILENO,&rd_fds))
- {
- len =read(STDIN_FILENO,rbuf,1023);
- rbuf[len] = '\0';
- printf("Read buf are: %s\n",rbuf);
- }
- }
- }
- exit(0);
- }
该函数是实现每个5秒钟,从标准输入读取数据;若超过5秒才写数据,则会返回0;输出结果:
- ff
- ret = 1
- Read buf are: ff
- ffh
- ret = 1
- Read buf are: ffh
- timeout,waiting next loop
- timeout,waiting next loop
- ^C
0 0
- 《unix高级环境编程》高级 I/O—— I/O 多路转接
- I/O多路转接 --- UNIX环境高级编程
- UNIX环境高级编程——I/O多路转接(select、pselect和poll)
- UNIX环境高级编程——非阻塞设置 && I/O多路转接
- 《unix高级环境编程》高级 I/O——非阻塞 I/O
- 《unix高级环境编程》高级 I/O—— I/O 多路复用
- 《unix高级环境编程》高级 I/O—— 存储映射 I/O
- 《unix高级环境编程》高级 I/O——非阻塞 I/O
- 《unix高级环境编程》高级 I/O—— 存储映射 I/O
- UNIX环境高级编程——文件I/O
- UNIX环境高级编程——标准I/O库
- UNIX环境高级编程——标准I/O库
- Unix环境高级编程——文件I/O
- 《UNIX环境高级编程》 —— I/O
- 《UNIX环境高级编程》读书笔记 —— 文件 I/O
- unix环境高级编程——文件i/o
- UNIX环境高级编程—文件I/O
- UNIX环境高级编程----文件I/O
- 关 于 PV 操 作
- rabbitmq 安装负载均衡配置
- 二讲:android 是什么?android 现有成员有哪些?
- IO流 System.in BufferedReader的readLine()方法 toUpperCase()方法 equalsIgnoreCase("exit")
- Servlet<4>
- 《unix高级环境编程》高级 I/O—— I/O 多路转接
- Ubuntu系统下Hadoop 2.0.4集群安装配置
- 中科院博士教你如何查找外文文献
- 第十三周项目六:体验文件操作3.0
- 《unix高级环境编程》高级 I/O—— readv 和 writev 函数
- 【计算几何初步-线段相交】【HDU1089】线段交点
- MediaPlayer和AudioTrack播放Audio的区别与联系
- 新旧代码兼容
- python 开始! Python 关于 name main的使用