好~~今天终于到最High的一部分,分析下载文件的主要过程了。这一切的一切,都在axel_do函数上。
先看前面部分:
- void axel_do( axel_t *axel )
- {
- fd_set fds[1];
- int hifd, i;
- long long int remaining,size;
- struct timeval timeval[1];
-
- /* Create statefile if necessary */
- if( gettime() > axel->next_state )
- {
- save_state( axel );
- axel->next_state = gettime() + axel->conf->save_state_interval;
- }
-
- /* Wait for data on (one of) the connections */
- 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;
- }
- }
这部分并不难,而且都有一定的注释,主要采用select模型(主要无连接有数据时跳转到conn_check函数,这个等会讲到)。接着看得到有数据的fd后怎样操作:
- 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;
- }
- else if( size == 0 )
- {
- if( axel->conf->verbose )
- {
- /* Only abnormal behaviour if: */
- if( axel->conn[i].currentbyte < axel->conn[i].lastbyte && axel->size != INT_MAX )
- {
- axel_message( axel, _("Connection %i unexpectedly closed"), i );
- }
- else
- {
- axel_message( axel, _("Connection %i finished"), i );
- }
- }
- if( !axel->conn[0].supported )
- {
- axel->ready = 1;
- }
- axel->conn[i].enabled = 0;
- conn_disconnect( &axel->conn[i] );
- continue;
- }
- /* remaining == Bytes to go */
- remaining = axel->conn[i].lastbyte - axel->conn[i].currentbyte + 1;
- if( remaining < size )
- {
- if( axel->conf->verbose )
- {
- axel_message( axel, _("Connection %i finished"), i );
- }
- axel->conn[i].enabled = 0;
- conn_disconnect( &axel->conn[i] );
- size = remaining;
- /* Don't terminate, still stuff to */
- }
- /* This should always succeed.. */
- lseek( axel->outfd, axel->conn[i].currentbyte, SEEK_SET );
- if( write( axel->outfd, buffer, size ) != size )
- {
-
- axel_message( axel, _("Write error!") );
- axel->ready = -1;
- return;
- }
- axel->conn[i].currentbyte += size;
- axel->bytes_done += size;
- }
- else
- {
- if( gettime() > axel->conn[i].last_transfer + axel->conf->connection_timeout )
- {
- if( axel->conf->verbose )
- axel_message( axel, _("Connection %i timed out"), i );
- conn_disconnect( &axel->conn[i] );
- axel->conn[i].enabled = 0;
- }
- } }
-
- if( axel->ready )
- return;
其实这部分也不难,仔细看代码都能知道怎样运作的,无非就是处理fd,把数据写到存储的文件中或者判断其他状况譬如完成、超时等等。
接着看一下如果没有连接的话会怎样做:
- conn_check:
- /* Look for aborted connections and attempt to restart them. */
- for( i = 0; i < axel->conf->num_connections; i ++ )
- {
- if( !axel->conn[i].enabled && axel->conn[i].currentbyte < axel->conn[i].lastbyte )
- {
- if( axel->conn[i].state == 0 )
- {
- // Wait for termination of this thread
- pthread_join(*(axel->conn[i].setup_thread), NULL);
-
- conn_set( &axel->conn[i], axel->url->text );
- axel->url = axel->url->next;
- /* axel->conn[i].local_if = axel->conf->interfaces->text;
- axel->conf->interfaces = axel->conf->interfaces->next; */
- if( axel->conf->verbose >= 2 )
- axel_message( axel, _("Connection %i downloading from %s:%i using interface %s"),
- i, axel->conn[i].host, axel->conn[i].port, axel->conn[i].local_if );
-
- axel->conn[i].state = 1;
- if( pthread_create( axel->conn[i].setup_thread, NULL, setup_thread, &axel->conn[i] ) == 0 )
- {
- axel->conn[i].last_transfer = gettime();
- }
- else
- {
- axel_message( axel, _("pthread error!!!") );
- axel->ready = -1;
- }
- }
- else
- {
- if( gettime() > axel->conn[i].last_transfer + axel->conf->reconnect_delay )
- {
- pthread_cancel( *axel->conn[i].setup_thread );
- axel->conn[i].state = 0;
- }
- }
- }
- }
这里其实也就是重新连接和超时的处理。
最后一个片段:
- /* Calculate current average speed and finish_time */
- axel->bytes_per_second = (int) ( (double) ( axel->bytes_done - axel->start_byte ) / ( gettime() - axel->start_time ) );
- axel->finish_time = (int) ( axel->start_time + (double) ( axel->size - axel->start_byte ) / axel->bytes_per_second );
- /* Check speed. If too high, delay for some time to slow things
- down a bit. I think a 5% deviation should be acceptable. */
- if( axel->conf->max_speed > 0 )
- {
- if( (float) axel->bytes_per_second / axel->conf->max_speed > 1.05 )
- axel->delay_time += 10000;
- else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) && ( axel->delay_time >= 10000 ) )
- axel->delay_time -= 10000;
- else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) )
- axel->delay_time = 0;
- usleep( axel->delay_time );
- }
-
- /* Ready? */
- if( axel->bytes_done == axel->size )
- axel->ready = 1;
- }
就是计算速度、预计完成时间和调整速度。呼呼~~~其实整个函数的核心就是一select模型。OK,睡觉~~
阅读(2043) | 评论(0) | 转发(1) |