IO多路复用_Select & poll

2019-04-13 21:07发布

1.  IO多路复用含义: IO 输入输出操作; 多路复用:若请求的IO操作阻塞,且它不是真正阻塞IO,而是让其中的一个函数等待,在这期间,IO 还能进行其他的操作。该函数有select() 和 poll()两个函数。 2. Selete()poll()函数: 设置程序中每一个所关心的文件描述符的条件、希望等待的时间等,selete()poll() 函数返回时内核会通知用户已经准备好的文件描述符的数量、已准备好的条件等。 通过使用selete()poll() 函数的返回结果,就可调用相应的IO处理函数; 2.1 Select()函数介绍: #include  #include  #include  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个, 也就是max8, 9, 10) + 1   select 函数注意点:http://blog.csdn.net/jkazan/article/details/52529687     2.3 poll() 函数介绍: #include  #include  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 #include #include #include #include #include #include #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! "); return 1; } if( (fds[2] = open("in2", O_RDONLY | O_NONBLOCK)) < 0) { printf("Open in2 is error! "); 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 ", tmp_inset); res = select( maxfd+1, &tmp_inset, NULL, NULL, &tv); printf("select return res = %d,准备好的fd数目 ", res); switch(res) { case -1:{ printf("Select error "); return 1; } break; case 0:{ printf("Time out "); 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] = '