select函数

axel中的axel_do函数中使用了select()函数,碰巧我正在看UNP的第六章讲的也是select函数,所以简单总结一下。

这里先列出axel_do函数中使用的select。

    FD_ZERO( fds );
    hifd = 0;
    for( i = 0; i < axel->conf->num_connections; i ++ )
    {
        if( axel->conn[i].enabled )
            FD_SET( axel->conn[i].fd, fds );
        hifd = max( hifd, axel->conn[i].fd );
    }
    if( hifd == 0 )
    {
        /* No connections yet. Wait...                */
        usleep( 100000 );
        goto conn_check;
    }
    else
    {
        timeval->tv_sec = 0;
        timeval->tv_usec = 100000;
        /* A select() error probably means it was interrupted
           by a signal, or that something else's very wrong...    */
        if( select( hifd + 1, fds, NULL, NULL, timeval ) == -1 )
        {
            axel->ready = -1;
            return;
        }
    }
    
    /* Handle connections which need attention            */
    for( i = 0; i < axel->conf->num_connections; i ++ )
    if( axel->conn[i].enabled ) {
    if( FD_ISSET( axel->conn[i].fd, fds ) )
    {
        axel->conn[i].last_transfer = gettime();
        size = read( axel->conn[i].fd, buffer, axel->conf->buffer_size );
        if( size == -1 )
        {
            if( axel->conf->verbose )
            {
                axel_message( axel, _("Error on connection %i! "
                    "Connection closed"), i );
            }
            axel->conn[i].enabled = 0;
            conn_disconnect( &axel->conn[i] );
            continue;
        }

为啥要使用select()

那么为啥需要使用select()函数呢?换句话说select函数的作用是啥?引用一句UNP上的话:

“select函数允许进程指示内核等待多个事件中的任何一个发生,并仅在有一个或多个事件发生或者经历一段指定的事件后才唤醒它。”

换句话说,有一个容器里面装了若干个事件,这些事件发生的顺序不清楚,但是发生之后要进行相应的处理。select函数的作用就是保持阻塞直到这些事件中的某一个发生,或者没事件发生的但过了一段指定的时间(超时时间)。

那么axel_do函数中使用的select的用意是啥呢?

其实从上面的代码中很容易看出来,这段代码的作用是要读有数据过来的socket。而axel在下载的时候是多连接的,我们不知道什么时候哪一个socket准备好了,于是不可能阻塞在一个socket上,取而代之的是阻塞在select函数上,直到有socket准备好,这样显然增加了效率。

先给出select()的原型:

int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);

·fd_set实际上是一个long的数组,fd_set数组中每一位对应一个描述符,就像是位(bit)一样,当某一位被置位,说明这一位对应的描述符在当前的描述符集合里。

timeout就是超时时间。

readfds,writefds,errorfds分别代表的是测试可读、可写、异常的描述符集合。

和select函数相关的四个宏:

FD_ZERO(fd_set *fdset)
FD_SET(int fd, fd_set *fdset)

FD_CLR(int fd, fd_set *fdset)
FD_ISSET(int fd, fdset *fdset)

清除fdset集合
将fd在fdset集合中置位,也就是将fd加入fdset
在fdset集合中清楚fd
测试fd是否在fdset中置位
原文地址:https://www.cnblogs.com/jaletech/p/3393336.html