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_CLR(int fd, fd_set *fdset)
|
清除fdset集合
将fd在fdset集合中置位,也就是将fd加入fdset 在fdset集合中清楚fd 测试fd是否在fdset中置位 |