上一篇分析了主要的数据结构和新建下载任务,嗯~准备开始下载了吧。下载之前,先得打开任务吧,打开任务之前,先得打开存储文件吧。。。。好。。。。
Axel把下载的内容存储在一个分配好每个连接的下载任务的文件上。看看下面的函数。
- /* Divide the file and set the locations for each connection */
- static void axel_divide( axel_t *axel )
- {
- int i;
-
- axel->conn[0].currentbyte = 0;
- axel->conn[0].lastbyte = axel->size / axel->conf->num_connections - 1;
- for( i = 1; i < axel->conf->num_connections; i )
- {
- #ifdef DEBUG
- printf( "Downloading %lld-%lld using conn. %i\n", axel->conn[i-1].currentbyte, axel->conn[i-1].lastbyte, i - 1 );
- #endif
- axel->conn[i].currentbyte = axel->conn[i-1].lastbyte 1;
- axel->conn[i].lastbyte = axel->conn[i].currentbyte axel->size / axel->conf->num_connections;
- }
- axel->conn[axel->conf->num_connections-1].lastbyte = axel->size - 1;
- #ifdef DEBUG
- printf( "Downloading %lld-%lld using conn. %i\n", axel->conn[i-1].currentbyte, axel->conn[i-1].lastbyte, i - 1 );
- #endif
- }
可以看得出来,Axel为每个建立的链接平均分配任务,也就是把文件内容平均分。
好,我们来看一下下面的函数:
- /* Open a local file to store the downloaded data */
- int axel_open( axel_t *axel )
- {
- int i, fd;
- long long int j;
-
- if( axel->conf->verbose > 0 )
- axel_message( axel, _("Opening output file %s"), axel->filename );
- snprintf( buffer, MAX_STRING, "%s.st", axel->filename );
-
- axel->outfd = -1;
-
- /* Check whether server knows about RESTart and switch back to
- single connection download if necessary */
- if( !axel->conn[0].supported )
- {
- axel_message( axel, _("Server unsupported, "
- "starting from scratch with one connection.") );
- axel->conf->num_connections = 1;
- axel->conn = realloc( axel->conn, sizeof( conn_t ) );
- axel_divide( axel );
- }
- else if( ( fd = open( buffer, O_RDONLY ) ) != -1 )
- {
- read( fd, &axel->conf->num_connections, sizeof( axel->conf->num_connections ) );
-
- axel->conn = realloc( axel->conn, sizeof( conn_t ) * axel->conf->num_connections );
- memset( axel->conn 1, 0, sizeof( conn_t ) * ( axel->conf->num_connections - 1 ) );
- axel_divide( axel );
-
- read( fd, &axel->bytes_done, sizeof( axel->bytes_done ) );
- for( i = 0; i < axel->conf->num_connections; i )
- read( fd, &axel->conn[i].currentbyte, sizeof( axel->conn[i].currentbyte ) );
- axel_message( axel, _("State file found: %lld bytes downloaded, %lld to go."),
- axel->bytes_done, axel->size - axel->bytes_done );
-
- close( fd );
-
- if( ( axel->outfd = open( axel->filename, O_WRONLY, 0666 ) ) == -1 )
- {
- axel_message( axel, _("Error opening local file") );
- return( 0 );
- }
- }
这是这个函数的前半部分,判断服务器能不能支持多个连接下载和端点续传,可以的话,然后再读取Buffer存储的信息,包括每个连接的已完成的下载字节和最近下载字节,否则直接跳过这一步进行分配每个连接的任务。嗯嗯,然后接下来打开存储数据的文件,描述符存在axel->outfd。
继续贴代码~~
- /* If outfd == -1 we have to start from scrath now */
- if( axel->outfd == -1 )
- {
- axel_divide( axel );
-
- if( ( axel->outfd = open( axel->filename, O_CREAT | O_WRONLY, 0666 ) ) == -1 )
- {
- axel_message( axel, _("Error opening local file") );
- return( 0 );
- }
-
- /* And check whether the filesystem can handle seeks to
- past-EOF areas.. Speeds things up. :) AFAIK this
- should just not happen: */
- if( lseek( axel->outfd, axel->size, SEEK_SET ) == -1 && axel->conf->num_connections > 1 )
- {
- /* But if the OS/fs does not allow to seek behind
- EOF, we have to fill the file with zeroes before
- starting. Slow.. */
- axel_message( axel, _("Crappy filesystem/OS.. Working around. :-(") );
- lseek( axel->outfd, 0, SEEK_SET );
- memset( buffer, 0, axel->conf->buffer_size );
- j = axel->size;
- while( j > 0 )
- {
- write( axel->outfd, buffer, min( j, axel->conf->buffer_size ) );
- j -= axel->conf->buffer_size;
- }
- }
- }
-
- return( 1 );
- }
如果存储的文件不存在,就新建一个。接着的注释挺详细,就是把文件指针指到文件末尾,“ 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函数:
- void axel_start( axel_t *axel )
- {
- int i;
-
- /* HTTP might've redirected and FTP handles wildcards, so
- re-scan the URL for every conn */
- for( i = 0; i < axel->conf->num_connections; i ++ )
- {
- 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;
- axel->conn[i].conf = axel->conf;
- if( i ) axel->conn[i].supported = 1;
- }
-
- if( axel->conf->verbose > 0 )
- axel_message( axel, _("Starting download") );
-
- for( i = 0; i < axel->conf->num_connections; i ++ )
- if( axel->conn[i].currentbyte <= axel->conn[i].lastbyte )
- {
- 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_message( axel, _("pthread error!!!") );
- axel->ready = -1;
- }
- else
- {
- axel->conn[i].last_transfer = gettime();
- }
- }
-
- /* The real downloading will start now, so let's start counting */
- axel->start_time = gettime();
- axel->ready = 0;
- }
首先,重新扫一遍每个连接。(暂时interface这个东东还不了解,貌似是网络对外的接口?)接下来为每个连接分配一个线程,我们看看setup_thread这个函数:
- /* Thread used to set up a connection */
- void *setup_thread( void *c )
- {
- conn_t *conn = c;
- int oldstate;
-
- /* Allow this thread to be killed at any time. */
- pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
- pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate );
-
- if( conn_setup( conn ) )
- {
- conn->last_transfer = gettime();
- if( conn_exec( conn ) )
- {
- conn->last_transfer = gettime();
- conn->enabled = 1;
- conn->state = 0;
- return( NULL );
- }
- }
-
- conn_disconnect( conn );
- conn->state = 0;
- return( NULL );
- }
其实从字面上大概了解这个函数的功能的,这个函数涉及到conn_t这个数据类型的功能,好的,下一篇就从这里开始看一下每个连接conn_t是怎样运作的。
PS:好像CU博客贴的代码不怎么好看?
阅读(2202) | 评论(0) | 转发(0) |