首页 > 代码库 > linux中select的使用方法
linux中select的使用方法
fd_set是一组文件描述符(fd,file descriptor)的集合,它用一位来表示一个fd。
系统提供了4个宏对描述符集进行操作:
#include <sys/select.h>
#include <sys/time.h>
//设置文件描述符集fdset中对应于文件描述符fd的位(设置为1)
void FD_SET(int fd, fd_set *fdset);
//清除文件描述符集fdset中对应于文件描述符fd的位(设置为0)
void FD_CLR(int fd, fd_set *fdset);
//清除文件描述符集fdset中的所有位(把所有位都设置为0)
void FD_ZERO(fd_set *fdset);
//在调用select后使用FD_ISSET来检测文件描述符集fdset中对应于文件描述符fd的位是否被置位。
void FD_ISSET(int fd, fd_set *fdset);
例如下面一段代码:
fd_set readset;
FD_ZERO(&readset);
FD_SET(5, &readset);
FD_SET(33, &readset);
则文件描述符集readset中对应于文件描述符5和33的相应位被置为1,如图1所示:
再执行如下程序后:
FD_CLR(5, &readset);
则文件描述符集readset对应于文件描述符5的相应位被置为0,如图2所示:
UNIX系统通常会在头文件<sys/select.h>中定义常量FD_SETSIZE,一般情况下被定义为1024,操作系统通过宏FD_SETSIZE来声明在一个进程中select所能操作的文件描述符的最大值(即fd_set包含的bit数)。我们可以在头文件中修改这个值来改变select使用的文件描述符集的大小,但是需要注意的是:必须重新编译内核才能使修改后的值有效。
FD_SETSIZE在linux下是值,限制文件描述符不能大于1024。
FD_SETSIZE在linux下也是数量,确定fd_set包含的bit数。
下面一段摘自man select中的原话:
"Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to or larger than FD_SETSIZE will result in undefined behavior."
select函数的原型如下:
#include <sys/types.h>
#include<sys/time.h>
int select (int maxfdp1,fd_set *readset,fd_set * writeset,fd_set excpetset,const struct timeval *timeout);
有三个可能的返回值。
1.正常情况下返回就绪的文件描述符个数,即对应bit仍然为1的fd的总数。
2.经过了timeval时长后仍无设备准备好,返回值为0;
3.如果出错,返回-1并设置相应的errno。
EBADF :文件描述词为无效的或该文件已关闭
EINTR :此调用被信号所中断
EINVAL :参数n 为负值
ENOMEM :核心内存不足
参数:
第一个参数maxfdp1:是所有加入文件描述符集的最大那个值还要加1。比如我们的文件描述符为1、4、5,那么maxfdp1就应该设置为6。
maxfdp1存在的目的是为提高效率,使函数不必检查fd_set的所有1024 bits。
maxfdp1,max file descriptor plus 1
第2、3、4三个参数:这三个参数都为文件描述符集合类型。
第2个:当文件描述符集合中有某个文件描述符的状态变成可读,系统就告诉select函数返回。
第3个:当文件描述符集合中有某个文件描述符的状态变成可写,系统就告诉select函数返回。
第4个:当文件描述符集合中有某个文件描述符有特殊情况发生时,系统会告诉select函数返回。
select返回后:三组fd_set类型的输入参数会被改变。将fd_set中无状态改变的fd的bit置0。那些可读、可写以及有异常条件待处理的fd的bit保持为1。
最后一个参数:timeval结构体的指针,timeval指定了秒数和微秒数。
struct timeval{
long tv_sec;//秒数
long tv_usec;//微秒数
};
timeval有三种可能:
1.timeval=NULL(阻塞式:直到有一个fd位被置为1,函数才返回)
2.timeval所指向的结构设为非零时间(等待固定时间:有一个fd位被置为1或者时间耗尽,函数均返回)
3.timeval所指向的结构,时间设为0(非阻塞:函数检查完每个fd后立即返回)
使用流程:
先调用宏FD_ZERO将指定的fd_set清零,
然后调用宏FD_SET将需要测试的fd加入fd_set,
接着调用函数select测试fd_set中的所有fd,并根据状态修改fd_set对应位,
最后用宏FD_ISSET检查某个fd在函数select调用后,相应位是否仍然为1。