首页 > 代码库 > 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。