IO多路复用_Select & poll
来源:互联网 发布:mac beta 转 正式版 编辑:程序博客网 时间:2024/06/02 00:09
1. IO多路复用含义:
IO: 输入输出操作;
多路复用:若请求的IO操作阻塞,且它不是真正阻塞IO,而是让其中的一个函数等待,在这期间,IO 还能进行其他的操作。该函数有select() 和 poll()两个函数。
2. Selete()和poll()函数:
设置程序中每一个所关心的文件描述符的条件、希望等待的时间等,selete()和poll() 函数返回时内核会通知用户已经准备好的文件描述符的数量、已准备好的条件等。
通过使用selete()和poll() 函数的返回结果,就可调用相应的IO处理函数;
2.1 Select()函数介绍:
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exeptfds, struct timeval *timeout);
参数说明:
函数参数
参数说明
备注
numfds
需要监视的文件描述符的最大值+1
readfds
select()监视的读文件描述符集合
writefds
监视的写文件描述符集合
exeptfds
监视的异常处理文件描述符集合
timeout
1) NULL ——永远等待,直到扑捉到信号;
2) 具体值——在等待的时间范围内,没有等到,则立即返回;
3) 0——从不等待,所有文件描述符立即返回
返回值
1) >0:成功,返回准备好的文件描述符的数目;
2) 0:超时;
3) -1:出错;
select() 文件描述符处理函数:
FD_ZERO(fd_set *set); 清除一个文件描述符集;
FD_SET(int fd, fd_set *set); 将文件描述符fd加入到文件描述符集合set中
FD_CLR(int fd, fd_set *set); 将一个文件描述符fd从文件描述符集合中删除;
FD_ISSET(int fd, fd_set *set);
//timeout数据类型介绍:
struct timeval
{
long tv_sec;
long tv_usec;
}
2.2 为什么linux select函数的第一个参数总应该是fdmax + 1 ?
这就涉及到linux select第一个参数的含义: 待测试的描述集的总个数。 但要注意, 待测试的描述集总是从0, 1, 2, ...开始的。 所以, 假如你要检测的描述符为8, 9, 10, 那么系统实际也要监测0, 1, 2, 3, 4, 5, 6, 7, 此时真正待测试的描述符的个数为11个, 也就是max(8, 9, 10) + 1
select 函数注意点:http://blog.csdn.net/jkazan/article/details/52529687
2.3 poll() 函数介绍:
#include <sys/types.h>
#include <poll.h>
int poll(struct pollfd *fds, int numfds, int timeout);
参数说明:
函数参数
参数说明
备注
fds
struct pollfd结构指针:描述需要对哪些文件的 哪种类型的操作进行监控;
struct pollfd {
int fd;
short events; //要监听的事件
short revents; //已发生的事件
}
events成员描述主要有以下几类:
POLLIN; POLLPRI; POLLOUT; POLLERR; POLLHUP; POLLNVAL;
numfds
要监听的文件描述符个数;
即第一个参数所指向的数组张哦功能的元素数目;
timeout
非0值: 等待的ms数;
<0: 无限等待;
返回值
1) >0:成功,事件发生的pollfd结构的个数;
2) 0:超时;
3) -1:出错;
3. 实例验证:
通过调用select() 函数来监听3个终端的输入,并分别进行相应的处理。3个文件描述符分别是:一个标准输入,两个管道文件描述符;通过监视主程序的输入终端来实现程序控制,比如结束程序;两个管道文件描述符作为输入,主程序将两个管道读取的输入字符串写入到标准输出文件,即屏幕上。
在标准终端输入‘q’ 或者 ’Q’时,监控终端退出,或者60S超时退出。
实验运行结果如下:
创建两个段管道,用命令:mknod in1 mknod in2
管道、网络编程等,都有阻塞作用。
管道中的数据,在下一次select()函数启动的时候,会调用读取管道里面的数据。
3.1 select() 程序代码:
#include <fcntl.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <time.h>#include <errno.h>#include <string.h>#define MAX_BUFF_SIZE 1024#define IN_FILES 3#define TIME_DELAY 60#define MAX(a, b) ((a > b) ? (a) : (b))int main(void){ int fds[IN_FILES]; char buff[MAX_BUFF_SIZE]; int i, res, real_read, maxfd; struct timeval tv; fd_set inset, tmp_inset; fds[0] = 0; if( (fds[1] = open("in1", O_RDONLY | O_NONBLOCK)) < 0 ) { printf("Open in1 is error!\n"); return 1; } if( (fds[2] = open("in2", O_RDONLY | O_NONBLOCK)) < 0) { printf("Open in2 is error!\n"); return 1; } maxfd = MAX( MAX(fds[0], fds[1]), fds[2]); FD_ZERO(&inset); for(i = 0; i < IN_FILES; i++) { FD_SET(fds[i], &inset); } FD_SET(0, &inset); tv.tv_sec = TIME_DELAY; tv.tv_usec = 0; while( FD_ISSET(fds[0], &inset) || FD_ISSET(fds[1], &inset) || FD_ISSET(fds[2], &inset) ) { tmp_inset = inset; //printf("tmp_inset = %d\n", tmp_inset); res = select( maxfd+1, &tmp_inset, NULL, NULL, &tv); printf("select return res = %d,准备好的fd数目\n", res); switch(res) { case -1:{ printf("Select error\n"); return 1; } break; case 0:{ printf("Time out\n"); return 1; } break; default:{for(i = 0; i < IN_FILES; i++){ if( FD_ISSET(fds[i], &tmp_inset) ) { memset(buff, 0, MAX_BUFF_SIZE); real_read = read(fds[i], buff, MAX_BUFF_SIZE); if(real_read < 0) { if(errno != EAGAIN) return 1; } else if( !real_read ) { close(fds[i]); FD_CLR(fds[i], &inset); } else { if( i == 0 ) { if( (buff[0] = 'q') || (buff[0] == 'Q') ) return 1; } else { buff[real_read] = '\0'; printf("Read Data is %s\n", buff); } } }} } } }}
select() 函数缺点:
1)内核必须检查多余的文件描述符;
2)每次调用select()函数之后,必须重置被监听的文件描述符集;
3)可监听的文件描述符受限;
4. poll()函数实例:
代码实现:
#include <fcntl.h> 2 #include <stdio.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <time.h> 7 #include <errno.h> 8 #include <poll.h> 9 10 #define MAX_BUFFSIZE 1024 11 #define IN_FILES 3 12 #define TIME_DELAY 100 13 #define MAX(a, b) ((a > b) ? (a) : (b)) 14 15 int main(void) 16 { 17 18 struct pollfd fds[IN_FILES]; 19 char buff[MAX_BUFFSIZE]; 20 int i, res, real_read, maxfd; 21 22 fds[0].fd = 0; 23 24 if( (fds[1].fd = open("in1", O_RDONLY | O_NONBLOCK)) < 0) 25 { printf("Open in1 Error\n"); 26 return 1; 27 } 28 29 if( (fds[2].fd = open("in2", O_RDONLY | O_NONBLOCK)) < 0) 30 { printf("Open in2 Error\n"); 31 return 1; 32 } 33 34 //1. 初始化所要监听的文件描述符的事件 35 for( i=0; i<IN_FILES; i++) 36 { 37 fds[i].events = POLLIN; 38 } 39 40 //2. 循环检测所监听的文件描述符的事件类型的事件是否发生:if( fds[i].revents ) 41 while( fds[0].events || fds[1].events || fds[2].events ) 42 { 43 //poll()函数,返回值为fds结构体的个数,即发生的文件描述>符的个数 44 if( (res = poll(fds, IN_FILES, 0)) < 0) 45 { printf("Poll error\n"); 46 return 1; 47 } 48 printf("1) poll fun returned is %d\n", res); 49 for(i=0; i<IN_FILES; i++) 50 { 51 printf("2) %d fds.fd is happened!\n",fds[i].fd); 52 53 //特别注意,该判断切勿遗漏: revents表示已发生的事件; events表示需要监听的事件的事件类型初始化; 54 if(fds[i].revents) 55 { 56 printf("3) %d fds.fd is happened!\n",fds[i].fd); 57 memset(buff, 0, MAX_BUFFSIZE); 58 real_read = read(fds[i].fd, buff, MAX_BUFFSIZE); 59 if(real_read < 0) 60 { if(errno != EAGAIN) 61 return 1; 62 } 63 else if( !real_read ) 64 { 65 close(fds[i].fd); 66 fds[i].events = 0; 67 } 68 else 69 { 70 //控制终端输入 q 或者 Q 时,退出程序运行; 71 if( 0 == i ) 72 { 73 if( (buff[0] == 'q') || (buff[0] == 'Q') ) 74 return 1; 75 } 76 else 77 { 78 buff[real_read] = '\0'; 79 printf("read data are %s\n", buff); 80 } 81 } 82 } 83 } 84 } 85 exit(0); 86 } 87 88
- IO多路复用_Select & poll
- IO多路复用之poll
- IO多路复用 - poll
- IO多路复用之poll
- poll-IO多路复用
- 多路复用IO&select&poll
- IO多路复用之poll
- 多路复用IO--poll
- IO多路复用之poll总结
- IO多路复用 select与poll
- IO多路复用之poll总结
- IO多路复用之poll总结
- IO多路复用之poll总结
- IO多路复用之poll总结
- IO多路复用之poll总结
- IO多路复用之poll总结
- IO多路复用之poll总结
- IO多路复用之poll总结
- 目标驱动测试过程改进——《The Little TMMi》
- SpringMVC接收json字符串转为List对象(数组对象)
- HDM接口执行定时刷新查询脚本
- java 网络流 TCP Socket和SeverSocket 互相交互对字符串进行大写转换
- redis之运维相关(10)
- IO多路复用_Select & poll
- [资源] Visual Studio 2015正式版离线iso及在线下载,附专业版和企业版可用key!
- MySQL中的异常处理,游标
- redis之主从复制(11)
- Task 11
- 在ubuntu 16.04上安装opencv和opencv_contrib
- 关于算法的时间复杂度
- 【poj1852】Ants 乱搞
- macOS安装homebrew命令