您的位置:首页 > 其它

关于事件驱动的学习二 select()

2010-06-25 11:35 183 查看
通过前面学习aio的过程,理解select()接口就简单了很多。
/* According to POSIX.1-2001 */
#include <sys/select.h>

/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);

void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
select 接口的主要功能是用于检查某个或某组的文件句柄 是否状态改变,譬如是否突然变可读,可写,timeout,或有exception等,如果这种改变(或称event)发生,则返回有状态改变的文件句柄的数量。

整个select的关键是: 如何将文件描述符(file descriptor) 跟一个个event联系起来。

select()的做法是,使用一个特征数fd_set. fd_set的每个位都表示一个fd值。举个例子,fd_set的25位则表示fd=25,fd_set的26位则表示fd=26。这样fd_set有多少位就可以标记多少个文件句柄。void FD_CLR(int fd, fd_set *set); 用以清除某fd对应在fd_set上的对应位
void FD_SET(int fd, fd_set *set); 用于标记fd对应在fd_set上的对应位
void FD_ZERO(fd_set *set);        用于至零
int FD_ISSET(int fd, fd_set *set);用于检查某个fd在fd_set上的对于位是否被标记
在看整个select接口:
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
参数nfds实际是多余的,用于指定最大的句柄值,当然,如果指定的话,就减少了轮循的长度,减少了系统负担。
譬如本次select调用涉及到的最大的句柄数值是233,则nfds最好设为234.
readfds  这是一个fd_set特征数。传地址是因为select()函数未来要修改此值。如果有两个文件需要检查是否出现readable事件,
那么在这两个fd需要用FD_SET()在readfds上设置自己的特征位。
writefds,exceptfds也是类似的功能,只是用来检测是否有writable事件和exception事件 。
select还有个重大的功能是能够坚持timeout事件。 有3种可能:
timeout=NULL,拥塞,知道有一个fd位被置为1,select函数才返回
timeout=NOT ZERO, 等待固定时间,有一个fd位被置为1或时间耗尽,则函数返回
timeout=zero,   非阻塞,函数检查完每个fd后立即返回。
返回对应位为1的fd的总数目。
 
注意timeval的结构。
struct timeval{
long tv_sec;  /* seconds */
long tv_usec; /* microseconds */
}

man select上就有个很好的例子,我稍做了修改:

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
fd_set rfds;
struct timeval tv;
int retval;

/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);          /* 清零         */
FD_SET(, &rfds);        /* 为stdin置位 */

/* Wait up to five seconds. */
tv.tv_sec = 5;              /*如果5秒内没有event,则退出*/
tv.tv_usec = 0;

retval = select(1, &rfds, NULL, NULL, &tv);  /* 只需哟扫描掉fd=1即可 */
/* Don't rely on the value of tv now! */     /* 注意select()是阻塞的 */

if (retval == -1)                /*返回出错*/
perror("select()");
else if (retval)                 /*返回说有多少文件接受到event,应该是1个*/
if(  FD_ISSET(0, &rfds)  )   /*确认STDIN确实能读了*/
printf("Data is available now./n");
else                             /*阻塞时间超过了5秒,但还是没有event*/
printf("No data within five seconds./n");

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息