Chinaunix首页 | 论坛 | 博客
  • 博客访问: 231201
  • 博文数量: 59
  • 博客积分: 1215
  • 博客等级: 少尉
  • 技术积分: 575
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-09 02:18
文章分类

全部博文(59)

文章存档

2012年(53)

2011年(6)

分类: C/C++

2012-01-16 01:40:51

     好~~今天终于到最High的一部分,分析下载文件的主要过程了。这一切的一切,都在axel_do函数上。
先看前面部分:
  1. void axel_do( axel_t *axel )
  2. {
  3.     fd_set fds[1];
  4.     int hifd, i;
  5.     long long int remaining,size;
  6.     struct timeval timeval[1];
  7.     
  8.     /* Create statefile if necessary                */
  9.     if( gettime() > axel->next_state )
  10.     {
  11.         save_state( axel );
  12.         axel->next_state = gettime() + axel->conf->save_state_interval;
  13.     }
  14.     
  15.     /* Wait for data on (one of) the connections            */
  16.     FD_ZERO( fds );
  17.     hifd = 0;
  18.     for( i = 0; i < axel->conf->num_connections; i ++ )
  19.     {
  20.         if( axel->conn[i].enabled )
  21.             FD_SET( axel->conn[i].fd, fds );
  22.         hifd = max( hifd, axel->conn[i].fd );
  23.     }
  24.     if( hifd == 0 )
  25.     {
  26.         /* No connections yet. Wait...                */
  27.         usleep( 100000 );
  28.         goto conn_check;
  29.     }
  30.     else
  31.     {
  32.         timeval->tv_sec = 0;
  33.         timeval->tv_usec = 100000;
  34.         /* A select() error probably means it was interrupted
  35.          by a signal, or that something else's very wrong...    */
  36.         if( select( hifd + 1, fds, NULL, NULL, timeval ) == -1 )
  37.         {
  38.             axel->ready = -1;
  39.             return;
  40.         }
  41.     }
        这部分并不难,而且都有一定的注释,主要采用select模型(主要无连接有数据时跳转到conn_check函数,这个等会讲到)。接着看得到有数据的fd后怎样操作:
  1. for( i = 0; i < axel->conf->num_connections; i ++ )
  2.     if( axel->conn[i].enabled ) {
  3.     if( FD_ISSET( axel->conn[i].fd, fds ) )
  4.     {
  5.         axel->conn[i].last_transfer = gettime();
  6.         size = read( axel->conn[i].fd, buffer, axel->conf->buffer_size );
  7.         if( size == -1 )
  8.         {
  9.             if( axel->conf->verbose )
  10.             {
  11.                 axel_message( axel, _("Error on connection %i! "
  12.                     "Connection closed"), i );
  13.             }
  14.             axel->conn[i].enabled = 0;
  15.             conn_disconnect( &axel->conn[i] );
  16.             continue;
  17.         }
  18.         else if( size == 0 )
  19.         {
  20.             if( axel->conf->verbose )
  21.             {
  22.                 /* Only abnormal behaviour if:        */
  23.                 if( axel->conn[i].currentbyte < axel->conn[i].lastbyte && axel->size != INT_MAX )
  24.                 {
  25.                     axel_message( axel, _("Connection %i unexpectedly closed"), i );
  26.                 }
  27.                 else
  28.                 {
  29.                     axel_message( axel, _("Connection %i finished"), i );
  30.                 }
  31.             }
  32.             if( !axel->conn[0].supported )
  33.             {
  34.                 axel->ready = 1;
  35.             }
  36.             axel->conn[i].enabled = 0;
  37.             conn_disconnect( &axel->conn[i] );
  38.             continue;
  39.         }
  40.         /* remaining == Bytes to go                    */
  41.         remaining = axel->conn[i].lastbyte - axel->conn[i].currentbyte + 1;
  42.         if( remaining < size )
  43.         {
  44.             if( axel->conf->verbose )
  45.             {
  46.                 axel_message( axel, _("Connection %i finished"), i );
  47.             }
  48.             axel->conn[i].enabled = 0;
  49.             conn_disconnect( &axel->conn[i] );
  50.             size = remaining;
  51.             /* Don't terminate, still stuff to     */
  52.         }
  53.         /* This should always succeed..                */
  54.         lseek( axel->outfd, axel->conn[i].currentbyte, SEEK_SET );
  55.         if( write( axel->outfd, buffer, size ) != size )
  56.         {
  57.             
  58.             axel_message( axel, _("Write error!") );
  59.             axel->ready = -1;
  60.             return;
  61.         }
  62.         axel->conn[i].currentbyte += size;
  63.         axel->bytes_done += size;
  64.     }
  65.     else
  66.     {
  67.         if( gettime() > axel->conn[i].last_transfer + axel->conf->connection_timeout )
  68.         {
  69.             if( axel->conf->verbose )
  70.                 axel_message( axel, _("Connection %i timed out"), i );
  71.             conn_disconnect( &axel->conn[i] );
  72.             axel->conn[i].enabled = 0;
  73.         }
  74.     } }
  75.     
  76.     if( axel->ready )
  77.         return;

     其实这部分也不难,仔细看代码都能知道怎样运作的,无非就是处理fd,把数据写到存储的文件中或者判断其他状况譬如完成、超时等等。

     接着看一下如果没有连接的话会怎样做:

  1. conn_check:
  2.     /* Look for aborted connections and attempt to restart them.    */
  3.     for( i = 0; i < axel->conf->num_connections; i ++ )
  4.     {
  5.         if( !axel->conn[i].enabled && axel->conn[i].currentbyte < axel->conn[i].lastbyte )
  6.         {
  7.             if( axel->conn[i].state == 0 )
  8.             {    
  9.                 // Wait for termination of this thread
  10.                 pthread_join(*(axel->conn[i].setup_thread), NULL);
  11.                 
  12.                 conn_set( &axel->conn[i], axel->url->text );
  13.                 axel->url = axel->url->next;
  14.                 /* axel->conn[i].local_if = axel->conf->interfaces->text;
  15.                 axel->conf->interfaces = axel->conf->interfaces->next; */
  16.                 if( axel->conf->verbose >= 2 )
  17.                     axel_message( axel, _("Connection %i downloading from %s:%i using interface %s"),
  18.                       i, axel->conn[i].host, axel->conn[i].port, axel->conn[i].local_if );
  19.                 
  20.                 axel->conn[i].state = 1;
  21.                 if( pthread_create( axel->conn[i].setup_thread, NULL, setup_thread, &axel->conn[i] ) == 0 )
  22.                 {
  23.                     axel->conn[i].last_transfer = gettime();
  24.                 }
  25.                 else
  26.                 {
  27.                     axel_message( axel, _("pthread error!!!") );
  28.                     axel->ready = -1;
  29.                 }
  30.             }
  31.             else
  32.             {
  33.                 if( gettime() > axel->conn[i].last_transfer + axel->conf->reconnect_delay )
  34.                 {
  35.                     pthread_cancel( *axel->conn[i].setup_thread );
  36.                     axel->conn[i].state = 0;
  37.                 }
  38.             }
  39.         }
  40.     }

       这里其实也就是重新连接和超时的处理。

 最后一个片段:

  1. /* Calculate current average speed and finish_time        */
  2.     axel->bytes_per_second = (int) ( (double) ( axel->bytes_done - axel->start_byte ) / ( gettime() - axel->start_time ) );
  3.     axel->finish_time = (int) ( axel->start_time + (double) ( axel->size - axel->start_byte ) / axel->bytes_per_second );

  4.     /* Check speed. If too high, delay for some time to slow things
  5.      down a bit. I think a 5% deviation should be acceptable.    */
  6.     if( axel->conf->max_speed > 0 )
  7.     {
  8.         if( (float) axel->bytes_per_second / axel->conf->max_speed > 1.05 )
  9.             axel->delay_time += 10000;
  10.         else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) && ( axel->delay_time >= 10000 ) )
  11.             axel->delay_time -= 10000;
  12.         else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) )
  13.             axel->delay_time = 0;
  14.         usleep( axel->delay_time );
  15.     }
  16.     
  17.     /* Ready?                            */
  18.     if( axel->bytes_done == axel->size )
  19.         axel->ready = 1;
  20. }
就是计算速度、预计完成时间和调整速度。呼呼~~~其实整个函数的核心就是一select模型。OK,睡觉~~
阅读(2043) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~