详解select,poll和epoll函数
select:
select的原型如下:
int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
n是需要监视的最大的文件描述符+1
select监视的fd分为三类,分别是readfds,writefds和exceptfds。调用select之后会阻塞,直到有描述符就绪,或者超时(timeout指定等待时间,如果设为null则立即返回),函数返回。
fd_set是一组fd的集合,它用一位来表示一个fd
可以使用宏操作fd_set:
fd_set set; FD_ZERO(&set); //clear all bits in set FD_SET(3, &set); //turn on bit 3 in set FD_CLR(2, &set); //clear bit 2 in set FD_ISSET(5, &set); //is bit 5 in set on?
select返回之后,通过遍历fdset,来找到就绪的描述符。
一个摘自csapp中的例子(只列出了关键代码):
// read_set is original set, ready_set is working set fd_set read_set, ready_set; listenfd = Open_listenfd(port); // call socket, bind...返回监听描述符 FD_ZERO(&read_set); FD_SET(STDIN_FILENO, &read_set) FD_SET(listenfd, &read_set) while(1){ ready_set = read_set; // suppose now ready_set : 0001 0001, bit 0 is STDIN_FILENO, bit 4 is listenfd select(listenfd+1, &ready_set, NULL, NULL, NULL); if (FD_ISSET(STDIN_FILENO, &ready_set)) // if only STDIN_FILENO is active, now ready_set: 0000 0001 command(); if (FD_ISSET(listenfd, &ready_set)) //if only listenfd is active, now ready_set: 0001 0000 connfd = accept(listenfd, (SA *)&clientaddr, &clientlen); echo(connfd); close(connfd); } //这里省略了command(), echo()函数的实现
select几乎在所有的平台上都支持,跨平台好。缺点主要是单个进程能监视的fd有限制,一般为1024.可通过其他方式调整。