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

全部博文(59)

文章存档

2012年(53)

2011年(6)

分类: LINUX

2012-01-14 16:23:31

     上一篇分析了主要的数据结构和新建下载任务,嗯~准备开始下载了吧。下载之前,先得打开任务吧,打开任务之前,先得打开存储文件吧。。。。好。。。。
     Axel把下载的内容存储在一个分配好每个连接的下载任务的文件上。看看下面的函数。
  1. /* Divide the file and set the locations for each connection        */
  2. static void axel_divide( axel_t *axel )
  3. {
  4.     int i;
  5.     
  6.     axel->conn[0].currentbyte = 0;
  7.     axel->conn[0].lastbyte = axel->size / axel->conf->num_connections - 1;
  8.     for( i = 1; i < axel->conf->num_connections; i )
  9.     {
  10. #ifdef DEBUG
  11.         printf( "Downloading %lld-%lld using conn. %i\n", axel->conn[i-1].currentbyte, axel->conn[i-1].lastbyte, i - 1 );
  12. #endif
  13.         axel->conn[i].currentbyte = axel->conn[i-1].lastbyte 1;
  14.         axel->conn[i].lastbyte = axel->conn[i].currentbyte axel->size / axel->conf->num_connections;
  15.     }
  16.     axel->conn[axel->conf->num_connections-1].lastbyte = axel->size - 1;
  17. #ifdef DEBUG
  18.     printf( "Downloading %lld-%lld using conn. %i\n", axel->conn[i-1].currentbyte, axel->conn[i-1].lastbyte, i - 1 );
  19. #endif
  20. }

     可以看得出来,Axel为每个建立的链接平均分配任务,也就是把文件内容平均分。

     好,我们来看一下下面的函数:

  1. /* Open a local file to store the downloaded data            */
  2. int axel_open( axel_t *axel )
  3. {
  4.     int i, fd;
  5.     long long int j;
  6.     
  7.     if( axel->conf->verbose > 0 )
  8.         axel_message( axel, _("Opening output file %s"), axel->filename );
  9.     snprintf( buffer, MAX_STRING, "%s.st", axel->filename );
  10.     
  11.     axel->outfd = -1;
  12.     
  13.     /* Check whether server knows about RESTart and switch back to
  14.      single connection download if necessary            */
  15.     if( !axel->conn[0].supported )
  16.     {
  17.         axel_message( axel, _("Server unsupported, "
  18.             "starting from scratch with one connection.") );
  19.         axel->conf->num_connections = 1;
  20.         axel->conn = realloc( axel->conn, sizeof( conn_t ) );
  21.         axel_divide( axel );
  22.     }
  23.     else if( ( fd = open( buffer, O_RDONLY ) ) != -1 )
  24.     {
  25.         read( fd, &axel->conf->num_connections, sizeof( axel->conf->num_connections ) );
  26.         
  27.         axel->conn = realloc( axel->conn, sizeof( conn_t ) * axel->conf->num_connections );
  28.         memset( axel->conn 1, 0, sizeof( conn_t ) * ( axel->conf->num_connections - 1 ) );

  29.         axel_divide( axel );
  30.         
  31.         read( fd, &axel->bytes_done, sizeof( axel->bytes_done ) );
  32.         for( i = 0; i < axel->conf->num_connections; i )
  33.             read( fd, &axel->conn[i].currentbyte, sizeof( axel->conn[i].currentbyte ) );

  34.         axel_message( axel, _("State file found: %lld bytes downloaded, %lld to go."),
  35.             axel->bytes_done, axel->size - axel->bytes_done );
  36.         
  37.         close( fd );
  38.         
  39.         if( ( axel->outfd = open( axel->filename, O_WRONLY, 0666 ) ) == -1 )
  40.         {
  41.             axel_message( axel, _("Error opening local file") );
  42.             return( 0 );
  43.         }
  44.     }

   这是这个函数的前半部分,判断服务器能不能支持多个连接下载和端点续传,可以的话,然后再读取Buffer存储的信息,包括每个连接的已完成的下载字节和最近下载字节,否则直接跳过这一步进行分配每个连接的任务。嗯嗯,然后接下来打开存储数据的文件,描述符存在axel->outfd。

   继续贴代码~~

  1. /* If outfd == -1 we have to start from scrath now        */
  2.     if( axel->outfd == -1 )
  3.     {
  4.         axel_divide( axel );
  5.         
  6.         if( ( axel->outfd = open( axel->filename, O_CREAT | O_WRONLY, 0666 ) ) == -1 )
  7.         {
  8.             axel_message( axel, _("Error opening local file") );
  9.             return( 0 );
  10.         }
  11.         
  12.         /* And check whether the filesystem can handle seeks to
  13.          past-EOF areas.. Speeds things up. :) AFAIK this
  14.          should just not happen:                */
  15.         if( lseek( axel->outfd, axel->size, SEEK_SET ) == -1 && axel->conf->num_connections > 1 )
  16.         {
  17.             /* But if the OS/fs does not allow to seek behind
  18.              EOF, we have to fill the file with zeroes before
  19.              starting. Slow..                */
  20.             axel_message( axel, _("Crappy filesystem/OS.. Working around. :-(") );
  21.             lseek( axel->outfd, 0, SEEK_SET );
  22.             memset( buffer, 0, axel->conf->buffer_size );
  23.             j = axel->size;
  24.             while( j > 0 )
  25.             {
  26.                 write( axel->outfd, buffer, min( j, axel->conf->buffer_size ) );
  27.                 j -= axel->conf->buffer_size;
  28.             }
  29.         }
  30.     }
  31.     
  32.     return( 1 );
  33. }

       如果存储的文件不存在,就新建一个。接着的注释挺详细,就是把文件指针指到文件末尾,“ But if the OS/fs does not allow to seek behind EOF, we have to fill the file with zeroes before
 starting. Slow..”

     呼~~~说了那么多,终于准备正式开始下载了。看axel_start函数:

 

  1. void axel_start( axel_t *axel )
  2. {
  3.     int i;
  4.     
  5.     /* HTTP might've redirected and FTP handles wildcards, so
  6.      re-scan the URL for every conn                */
  7.     for( i = 0; i < axel->conf->num_connections; i ++ )
  8.     {
  9.         conn_set( &axel->conn[i], axel->url->text );
  10.         axel->url = axel->url->next;
  11.         axel->conn[i].local_if = axel->conf->interfaces->text;
  12.         axel->conf->interfaces = axel->conf->interfaces->next;
  13.         axel->conn[i].conf = axel->conf;
  14.         if( i ) axel->conn[i].supported = 1;
  15.     }
  16.     
  17.     if( axel->conf->verbose > 0 )
  18.         axel_message( axel, _("Starting download") );
  19.     
  20.     for( i = 0; i < axel->conf->num_connections; i ++ )
  21.     if( axel->conn[i].currentbyte <= axel->conn[i].lastbyte )
  22.     {
  23.         if( axel->conf->verbose >= 2 )
  24.         {
  25.             axel_message( axel, _("Connection %i downloading from %s:%i using interface %s"),
  26.               i, axel->conn[i].host, axel->conn[i].port, axel->conn[i].local_if );
  27.         }
  28.         
  29.         axel->conn[i].state = 1;
  30.         if( pthread_create( axel->conn[i].setup_thread, NULL, setup_thread, &axel->conn[i] ) != 0 )
  31.         {
  32.             axel_message( axel, _("pthread error!!!") );
  33.             axel->ready = -1;
  34.         }
  35.         else
  36.         {
  37.             axel->conn[i].last_transfer = gettime();
  38.         }
  39.     }
  40.     
  41.     /* The real downloading will start now, so let's start counting    */
  42.     axel->start_time = gettime();
  43.     axel->ready = 0;
  44. }
       首先,重新扫一遍每个连接。(暂时interface这个东东还不了解,貌似是网络对外的接口?)接下来为每个连接分配一个线程,我们看看setup_thread这个函数:
  1. /* Thread used to set up a connection                    */
  2. void *setup_thread( void *c )
  3. {
  4.     conn_t *conn = c;
  5.     int oldstate;
  6.     
  7.     /* Allow this thread to be killed at any time.            */
  8.     pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
  9.     pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate );
  10.     
  11.     if( conn_setup( conn ) )
  12.     {
  13.         conn->last_transfer = gettime();
  14.         if( conn_exec( conn ) )
  15.         {
  16.             conn->last_transfer = gettime();
  17.             conn->enabled = 1;
  18.             conn->state = 0;
  19.             return( NULL );
  20.         }
  21.     }
  22.     
  23.     conn_disconnect( conn );
  24.     conn->state = 0;
  25.     return( NULL );
  26. }

      其实从字面上大概了解这个函数的功能的,这个函数涉及到conn_t这个数据类型的功能,好的,下一篇就从这里开始看一下每个连接conn_t是怎样运作的。

PS:好像CU博客贴的代码不怎么好看?

阅读(2217) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~