linux I/0复用函数之 ------ select()

一、函数原型:

#include 
#include 

int select(int nfds, fd_set *rdfds, fd_set *wtfds,
                fd_set *exfds, struct timeval *timeout)

二、函数说明:

        I/O多路复用系统函数,select()用来等待文件描述词(普通文件、终端、伪终端、管道、FIFO、套接字及其他类型的字符型)状态的改变。select()会一直阻塞,直到一个或多个文件描述符集合称为就绪态或者指定一个超时时间。但是不适合文件数量庞大、I/0流量频繁的时候,它会随着fd的数量增大性能下降明显。

 

三、参数说明:

nfds:select中监视的文件句柄数,一般设为要监视的文件中的最大文件号加一。该参数让select变得更有效率,因为此时内核就不用去检查大于这个值的文件描述符是否属于这些文件描述符集合。文件描述符集合有一个最大容量限制,由常量FD_SETSIZE来决定,一般最大位1024个描述符

readfds:检测输入是否就绪的文件描述符集合

writefds :检测输出是否就绪的文件描述符集合

exceptfds:检测异常情况是否发生的文件描述符集合(1、信包模式下伪终端主设备上从设备状态发生改变;2、流式套接字接                                                                                            收到了外带数据)

数据类型fd_set以位掩码的形式来实现,通过四个宏来完成:

FD_CLR(inr fd,fd_set* set);将描述符fd从fdset所指向的集合中移除

FD_SET(int fd,fd_set*set);将描述符fd添加到fdset所指向的集合中

FD_ZERO(fd_set *set); 将fdset指向的集合初始化位空

FD_ISSET(int fd,fd_set *set);测试描述词组set中相关fd 的位是否为真

        参数readfds、writefds、excptfds所指向的结构体都是保存结果值的地方。再调用select()之前,这些参数所指向的结构体必须初始化(通过FD_ZERO和FD_SET),以包含我们感兴趣的文件描述符集合。之后select()会修改这些结构体,当select()返回时,它们包含的就是已处于就绪态的文件描述符集合了。(由于这些结构体会在调用中修改,如果要在循环中重复使用select(),我们必须保证每次都要重新初始化它们)。之后这些结构体可以通过FD_ISSET来检查。

timeout:

struct timeval {

          time_t tv_sec;  秒

          suseconds_t tv_usec  微秒

}

这个参数它使select处于三种状态,

1、若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;

2、若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;

3、,timeout的值大于0,等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。

返回值:

负值:select错误

0:等待超时,没有可读写或错误的文件

正值:1个或者多个文件描述符达到就绪态,返回值表示就绪态的文件描述符个数。

 

 

四、代码举例:

//Linux下监控键盘上是否有数据到来?

#include   
#include   
#include   
#include   
#include   
#include   

int main (void)  
{  
    int keyboard;  
    int ret,i;  
    char c;  
    fd_set readfd;  
    struct timeval timeout;  
    keyboard = open("/dev/tty",O_RDONLY | O_NONBLOCK);  
    assert(keyboard>0);

    while(1)  
    {  
        timeout.tv_sec=1;  
        timeout.tv_usec=0;  
        FD_ZERO(&readfd);  
        FD_SET(keyboard,&readfd);  
  
        ///监控函数  
        ret = select(keyboard+1,&readfd,NULL,NULL,&timeout);  
        if(ret == -1)   //错误情况  
            printf("error!\n");  
        else if(ret)    //返回值大于0 有数据到来  
            if(FD_ISSET(keyboard,&readfd))  
            {  
                i=read(keyboard,&c,1);  
                if('\n'==c)  
                    continue;  
                printf("the input is %c\n",c);  
                if ('q'==c)  
                    break;  
            }  
        else    //超时情况  
        {  
            printf("time out!\n"); 
            continue;  
        }  
    }  
}  

 

 

 

 

 

你可能感兴趣的:(linux)