通过前面学习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(STDIN, &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;
} |
本文深入解析Linux环境下select()接口的工作机制,包括其关键参数、功能及应用示例,帮助读者理解如何有效利用select()进行并发文件句柄监控。
170万+

被折叠的 条评论
为什么被折叠?



