linux---select函数用法详解

函数主要功能

调用select函数,可以让进程指示内核等待多个事件中的任意一个发生,并使进程处于阻塞状态,直到select参数指定的事情或者关心的事情发生时候,才唤醒进程,并且函数返回准备就绪的事件个数。

 

函数原型:

#include<sys/select.h>

int select(int maxfdp1 , fd_set*restrict readfds, fd_set *restrict writefds ,fd_set*restrict exceptfds, struct timeval*restruct tvptr);

 

select的参数主要告诉内核

1)我们关注的描述符(如socket套接字返回的描述符)

2)对于每个描述符我们所关心的条件(是否想从一个给定的描述符读,是否想写一个给定的描述符,是否关心一个给定描述符的异常条件)

3)最长的等待时间

Select函数返回的时候,内核告诉我们:

1)已经准备好的描述符的总数量

2)对于读、写、或者异常者3个条件中的每一个,有哪一些描述符是准备好的

 

参数解释:

 

maxfd1是所有描述符中最大值的描述符+1,这个参数告诉内核我们所关注的最大的描述符,

内核只需要在最大的描述符范围内查找打开的位就可以。

 

timeval类型的参数tvptr执行select函数等待时间发生的时间长度,tvptr==NULL的时候,表示永远等待,当执行的描述符中有一个已准备好时候等待状态结束。

tvptr->tv_sec==0&&tvptr->tv_usec==0时,select不等待,测试完所以制定的描述符后立即返回,这是轮询系统找到多个描述符而不阻塞select函数的方法

tvptr->tv_sec!=0||tvptr->tv_usec!=0 等待的时间

 

Readfds,writefds,exceptfds;三个都是指向描述符集的指针,这3个描述符集说明了我们关心的可读、可写或者处于异常条件的描述符集合,没个描述符集合都存储在fd_set数据类型中.

对于fd_set数据类型,我们可以直接将它赋值给相同类型的数据类型,以及通过以下四个函数进行操作

 

#include<sys/select.h>

Int FD_ISSET(int fd,fd_set* fset) 

//判断一个文件描述符是否在集合内,在未调用select函数的时候,调用FD_ISSET时候,如果一个文件描述符在集合fset中,那么返回真,否者返回假,如果已经调用了select函数,select函数返回之后,如果文件描述符fd在集合fset中,并且文件描述符已经准备好可以被读或被写,那么调用FD_ISSET返回的是真,付过文件符fd有准备好,那么即使fd在集合

fset中,FD_ISSET返回的还是假

 

这里“准备好”指的是进程可以直接对文件描述符进行读写而不处于阻塞状态,例如对于read函数,如果当前可以从网络中读取远程发来的数据,那么read所操作的文件描述符就处于准备好的状态,如果read没有数据读取,处于阻塞状态,那么read所操作的文件描述符就没有准备好

 

void FD_CLR(int fd,fd_set*fset);//清除fd

void FD_SET(int fd,fd_set*fset);//fd添加到集合fd_set

void FD_ZERO(int fd,fd_set*fset);//清空fd_set

#include<stdio.h>
#include<sys/select.h>
#include<unistd.h>

/*程序目的:
验证select函数监测的文件描述符准备好可以被读取时就立即返回,并且FD_SET()相应的文件描述符返回的是真,如果监测的文件描述符没有
准备好,返回的是假
*/
int main()
{
    int max;
    fd_set readfds,writefds,temps;
    struct timeval tvptr;

    FD_ZERO(&readfds);//在使用fd_set变量时一定要进行初始化
    FD_SET(STDIN_FILENO,&readfds);
    
    temps=readfds;//fd_set同类型的变量可以直接赋值

    FD_ZERO(&writefds);
    FD_SET(STDOUT_FILENO,&writefds);

    tvptr.tv_sec=3;//将等待时间设置为3.5秒
    tvptr.tv_usec=500000;

	/*
	1)使用select函数监测STDOUT_FILENO,STDIN_FILENO
	*/

    max=STDOUT_FILENO>STDIN_FILENO?STDOUT_FILENO:STDIN_FILENO;//求最大的文件描述符

	/*select使进程处于阻塞状态,知道时间到了或者所关心的实践到来,如STDOUT_FILENO或者STDIN_FILENO
	可读,那么select函数就会返回,进程继续执行*/
    select(max+1,&readfds,&writefds,NULL,&tvptr);

	/*如果STDIN_FILENO或STDOUT_FILENO准备可以被读取,那么就会输出提示*/

    if(FD_ISSET(STDIN_FILENO,&readfds))
    {
		/*由于STDOUT_FILENO对于进程来说始终是可输出的已准备好状态,所以执行的之后select没有等STDIN_FILENO准备好
		就直接返回,虽然STDIN_FILENO在readfds中,但是STDIN_FILENO仍是未准备好状态,所以FD_ISSET()返回的是false,
		这句永远不会输出*/
        printf("STDIN_FILENO is seted\n");
    }

    if(FD_ISSET(STDOUT_FILENO,&writefds))
    {
        printf("STDOUT_FILENO is seted\n");
    }


	/*2)使用select函数只监测STDIN_FILENO*/
	/*调用之后,readfds和writefds都会被清空,以下进行验证*/
    if(FD_ISSET(STDIN_FILENO,&readfds))
    {
        printf("STDIN_FILENO is still in readfds\n");
    }
    else
    {
        printf("STDIN_FILENO is not in readfds\n");
    }
    //FD_SET(STDIN_FILENO,&readfds);
	/*单独监测STDIN_FILENO,在规定的时间内如果标准输入准备好(按回车)着输出提示*/
	FD_ZERO(&writefds);
    readfds=temps;//temps以保存readfds的值
    max=max>STDIN_FILENO?max:STDIN_FILENO;
    select(max+1,&readfds,&writefds,NULL,&tvptr);

    if(FD_ISSET(STDIN_FILENO,&readfds))
    {
        printf("STDIN_FILENO is settd\n");

        /*if(FD_ISSET(STDOUT_FILENO,&writefds))
            printf("STDOUT_FILENO is seted\n");*/
    }
    else
    {
        printf("time over\n");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值