select机制

select机制

函数作用:

在一段时间指定的时间内,监听用户感兴趣的文件描述符上可读、可写和异常事件。

函数原型:
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数说明:

maxfds:

maxfds:是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错。
在linux系统中,select的默认最大值为1024。
设置这个值的目的是为了不用每次都去轮询这1024个fd,假设我们只需要几个套接字,我们就可以用最大的那个套接字的值加上1作为这个参数的值,当我们在等待是否有套接字准备就绪时,只需要监测maxfd+1个套接字就可以了,这样可以减少轮询时间以及系统的开销。

readfds:

readfds:首先需要明白,fd_set是什么数据类型,有一点像int,又有点像struct,其实,fd_set声明的是一个集合,也就是说,readfs是一个容器,里面可以容纳多个文件描述符,把需要监视的描述符放入这个集合中,当有文件描述符可读时,select就会返回一个大于0的值,表示有文件可读;

writefds:

和readfs类似,表示有一个可写的文件描述符集合,当有文件可写时,select就会返回一个大于0的值,表示有文件可写;

errorfds

同上面两个参数的意图,用来监视文件错误异常文件。

timeout:

这个参数一出来就可以知道,可以选择阻塞,可以选择非阻塞,还可以选择定时返回。
当将timeout置为NULL时,表明此时select是阻塞的;
当将tineout设置为timeout->tv_sec = 0,timeout->tv_usec = 0时,表明这个函数为非阻塞;
当将timeout设置为非0的时间,表明select有超时时间,当这个时间走完,select函数就会返回。
从这个角度看,个人觉得可以用select来做超时处理,因为你如果使用recv函数的话,你还需要去设置recv的模式,麻烦的很。

返回值

= 0 表示超时
< 0 select失败
> 0 成功,表示就绪的描述符的个数

举例1:创建一个线程,每100ms轮训一次,使用select设置timeout时间。

struct timeval
{      
    long tv_sec;   /*秒 */
    long tv_usec;  /*微秒 */   
};

int func1()
{
    struct timeval time;
    time->tv_sec = 0;
    time->tv_usec = 100000;
    int32_t ret = select(0, nullptr, nullptr, nullptr, time);
    if (ret == 0) {
        // 100ms超时时间到,可以处理相应的task等
    } else if (ret < 0) {
        // 函数select出错
    } else {
        // 不会出现这种情况,因为我们没有监听任何描述符
    }
    return 1;
}
int main()
{
    while(func1() == 1){}; // 一直循环处理,每100ms处理一次task
}
####select总结:
1、使用select监听socket时是线性扫描的方式,即采用轮询的方式,当套接字比较多的时候,每次select都要遍历每个socket来完成调度,不管哪个socket是活跃的,都会遍历一遍,这很浪费CPU的时间,如果每个套接字都能注册一个回调函数,当套接字活跃时直接调用回调也是很方便的,这样就避免了轮训,这正是epoll和equeue做的事情。

2、

原文地址:https://www.cnblogs.com/wangdongfang/p/13849932.html