免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: duanjigang
打印 上一主题 下一主题

源码阅读第一期:axel和wget [复制链接]

论坛徽章:
0
91 [报告]
发表于 2011-10-02 20:49 |只看该作者
回复  wangzhen11aaa
不会陷入死循环,因为是在if语句中,编译成汇编时在if模块里是不会跳转到else语句中 ...
wangzhen11aaa 发表于 2011-10-02 19:46



    辛苦!

论坛徽章:
0
92 [报告]
发表于 2011-10-02 21:25 |只看该作者
_____________------------>
191           c = X2DIGITS_TO_NUM (h[1], h[2]);/*____________----------->/src/wget.h*/
192           /* Don't unescape %00 because there is no way to insert it
193              into a C string without effectively truncating it.,不要丢掉%00的情况,因为无法插入c字符串无法有效截断它 */
194           if (c == '\0')
195             goto copychar;
196           *t = c; /*转化后赋值给指针指向的地方。
197           h += 2;
198         }
199     }
200   *t = '\0';
201 }

#define X2DIGITS_TO_NUM(h1, h2) ((XDIGIT_TO_NUM (h1) << 4) + XDIGIT_TO_NUM (h2))  
#define XDIGIT_TO_NUM(h) ((h) < 'A' ? (h) - '0' : c_toupper (h) - 'A' + 10)
/*此处判断%号后面如果不为NULL ,而且都为16 进制数的话,那么就进行宏定义的判断,将这些字符转化成十进制的ASCII码,后面加的是加10是转化到10-15之间的数,16进制a以上至少为10。*/
/*此处<<4因为是高四位*/
<---------------------____________________________
转化第一个字符串。返回到append_uri_pathel()
1393       b = unescaped;
1394       e = unescaped + strlen (unescaped);/*这是期望的那个字符串地址。
1399   if (e - b == 2 && b[0] == '.' && b[1] == '.')
1400     {
1401       b = "%2E%2E";
1402       e = b + 6;
1403     }   /*如果发现期望字符串和input字符串之间地址差二,而iput地址为b[0],b[1]那么就就上述那样,期望地址从b+6的地方开始,提防恶意输入*/
1407   quoted = 0;
1408   for (p = b; p < e; p++)
1409     if (FILE_CHAR_TEST (*p, mask))  /*遍历路径字符串,看看需要多少字符串1、_____------->url.c*/
1410       ++quoted;
1、______--------->
1300 #define FILE_CHAR_TEST(c, mask) \
1301     ((opt.restrict_files_nonascii && !c_isascii ((unsigned char)(c))) || \  /*这两个判断字符值是否大于127,上面这个式子非常妙,自己分析吧*/
1302     (filechr_table[(unsigned char)(c)] & (mask)))  /*mask 是前面的一系列赋值, filechr_table是数量为256个的表。如果c的值大于127那么会用两个8进制数据来表示或者当在filechar_table中命中,那么此值为int类型。*/
1415   outlen = (e - b) + (2 * quoted);
1416   GROW (dest, outlen);
1417
1418   if (!quoted)
1419     {
1420       /* If there's nothing to quote, we can simply append the string
1421          without processing it again.  */
1422       memcpy (TAIL (dest), b, outlen);  /*如果没有要引用的,那么拷贝到dest的尾部*/
1423     }
1424   else
1425     {
1426       char *q = TAIL (dest);
1427       for (p = b; p < e; p++)
1428         {
1429           if (!FILE_CHAR_TEST (*p, mask))  /*如果没有可以引用的值就拷贝过去*/
1430             *q++ = *p;   
1431           else
1432             {
1433               unsigned char ch = *p;
1434               *q++ = '%';                 /*否则用这种格式来来处理,再转化成字符原来16进制形式*/
1435               *q++ = XNUM_TO_DIGIT (ch >> 4);
1436               *q++ = XNUM_TO_DIGIT (ch & 0xf);
1437             }
1438         }
1439       assert (q - TAIL (dest) == outlen); /*断言是否相等*/
1440     }
1441
1442   /* Perform inline case transformation if required.  */
1443   if (opt.restrict_files_case == restrict_lowercase
1444       || opt.restrict_files_case == restrict_uppercase)
1445     {
1446       char *q;
1447       for (q = TAIL (dest); q < TAIL (dest) + outlen; ++q)
1448         {
1449           if (opt.restrict_files_case == restrict_lowercase)
1450             *q = c_tolower (*q);  /*给输出部分改变格式*/
1451           else
1452             *q = c_toupper (*q);
1453         }
1454     }
1455
1456   TAIL_INCR (dest, outlen); /*改变末端地址*/
1457 }

<------------------____________________
回到 test_append_uri_pathel()

2232       append_char ('\0', &dest);_________-------------->/src/url.c*/
2233
2234       mu_assert ("test_append_uri_pathel: wrong result",
2235                  strcmp (dest.base, test_array[i].expected_result) == 0); /*比较dest的字符串和期望的是否相同。不相等的话就打印出错误值
2236     }
________------------>
1287 append_char (char ch, struct growable *dest)
1288 {
1289   GROW (dest, 1);
1290   *TAIL (dest) = ch;
1291   TAIL_INCR (dest, 1);  /*给最后的字符串加\0*/
1292 }

论坛徽章:
0
93 [报告]
发表于 2011-10-02 21:28 |只看该作者
回复 91# duanjigang
其实没有什么,主要是linux工具那么神奇。我只不过是分析分析,辛苦不算,有兴趣就没事了。

论坛徽章:
0
94 [报告]
发表于 2011-10-03 09:45 |只看该作者
<-------------___________________
返回到all_tests()
{
. . . . .
mu_run_test(test_are_urls_equal); /*1、_______------->/src/url.c */
. . . . . .
}
1、____________------------>
2241 const char*
2242 test_are_urls_equal()
2243 {
2244   int i;
2245   struct {
2246     char *url1;
2247     char *url2;
2248     bool expected_result;
2249   } test_array[] = {
2250     { "http://www.adomain.com/apath/", "http://www.adomain.com/apath/",       true },
2251     { "http://www.adomain.com/apath/", "http://www.adomain.com/anotherpath/", false },
2252     { "http://www.adomain.com/apath/", "http://www.anotherdomain.com/path/",  false },
2253     { "http://www.adomain.com/~path/", "http://www.adomain.com/%7epath/",     true },/*%7e为特殊用法见上节分析*/
2254     { "http://www.adomain.com/longer-path/", "http://www.adomain.com/path/",  false },
2255     { "http://www.adomain.com/path%2f", "http://www.adomain.com/path/",       false },
2256   };
2257
2258   for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i)
2259     {
2260       mu_assert ("test_are_urls_equal: wrong result",
2261                  are_urls_equal (test_array[i].url1, test_array[i].url2) == test_array[i  ].expected_result); /*2、_______________----------->src/url.c*/
2262     }
2263
2264   return NULL;
2265 }
2_______________------------------>
2094 bool
2095 are_urls_equal (const char *u1, const char *u2)
2096 {
2097   const char *p, *q;
2098   int pp, qq;
2099   char ch1, ch2;
2100   assert(u1 && u2);
2101
2102   p = u1;
2103   q = u2;
2104
2105   while (*p && *q
2106          && (pp = getchar_from_escaped_string (p, &ch1)) /*3、________-------->/src/url.c*/
2107          && (qq = getchar_from_escaped_string (q, &ch2))
2108          && (c_tolower(ch1) == c_tolower(ch2)))  /*两个字符是否向等*/
2109     {
2110       p += pp;
2111       q += qq; /*依次递增值,刚才返回*/
2112     }
2113
2114   return (*p == 0 && *q == 0 ? true : false); /*看最后返回的是否两个字符串都到末尾*/

3、______________-------------------->
2056 static int
2057 getchar_from_escaped_string (const char *str, char *c)
2058 {
2059   const char *p = str;
2060
2061   assert (str && *str);
2062   assert (c);
2063
2064   if (p[0] == '%')
2065     {
2066       if (!c_isxdigit(p[1]) || !c_isxdigit(p[2]))/*如果是16进制的数什么也不做*/
2067         {
2068           *c = '%';
2069           return 1;
2070         }
2071       else
2072         {
2073           if (p[2] == 0)
2074             return 0; /* error: invalid string */
2075
2076           *c = X2DIGITS_TO_NUM (p[1], p[2]); /*将其转化成0-15之间对应的数,并存放在c指向的地址*/
2077           if (URL_RESERVED_CHAR(*c)) /*4、_______------------>src/url.c*/
2078             {
2079               *c = '%';
2080               return 1;
2081             }
2082           else
2083             return 3;
2084         }
2085     }
2086   else
2087     {
2087     {
2088       *c = p[0]; /*正常的赋值*/
2089     }
2090
2091   return 1;
2092 }
4、__________________----------------->
122 #define URL_RESERVED_CHAR(c) urlchr_test(c, urlchr_reserved)
121 #define urlchr_test(c, mask) (urlchr_table[(unsigned char)(c)] &(mask)) /*去一个数组里面检查这个字符的真实含义 如果返回为空的话,那么就说明这是%xx格式,要返回3个字节*/
<--------------_______________________
返回all_test()
     检查url是否等价完毕

论坛徽章:
0
95 [报告]
发表于 2011-10-03 10:17 |只看该作者
<-------------______________
返回到all_tests()
{
. . . . . /*The last one is coming*/
mu_run_test(test_is_robots_txt_url); /*和那spider有关1、_____________------------->src/res.c*/
. . . . . .
}
1、____________-------------->
618 test_is_robots_txt_url()
619 {
620   int i;
621   struct {
622     char *url;
623     bool expected_result;
624   } test_array[] = {
625     { "http://www.yoyodyne.com/robots.txt", true },  /*因为此文件在服务器根目录所以只有它是正确的*/
626     { "http://www.yoyodyne.com/somepath/", false },
627     { "http://www.yoyodyne.com/somepath/robots.txt", false },
628   };
629   
630   for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i)
631     {
632       mu_assert ("test_is_robots_txt_url: wrong result",
633                  is_robots_txt_url (test_array[i].url) == test_array[i].expected_result);
                         /*2、_________------------>/src/res.c*/
634     }
635
636   return NULL;
637 }
2、_____________--------------->
586 bool
587 is_robots_txt_url (const char *url)
588 {
589   char *robots_url = uri_merge (url, RES_SPECS_LOCATION); /*3、________------------>/src/url.c*/
590   bool ret = are_urls_equal (url, robots_url);
591
592   xfree (robots_url);
593
594   return ret;
595 }
3、____________----------------->
#define RES_SPECS_LOCATION "/robots.txt"
1743 uri_merge (const char *base, const char *link)
1744 {
1745   int linklength;
1746   const char *end;
1747   char *merge;
1748
1749   if (url_has_scheme (link))4、_________---------->src/url.c*/
1750     return xstrdup (link); 5、__________----------->/xmalloc.c*/
1751      
1752   /* We may not examine BASE past END. */
1753   end = path_end (base);
1754   linklength = strlen (link);
1755
1756   if (!*link)
1757     {
1758       /* Empty LINK points back to BASE, query string and all. */
1759       return xstrdup (base);
1760     }
1761   else if (*link == '?')
1762     {
1763       /* LINK points to the same location, but changes the query
1764          string.  Examples: */
1765       /* uri_merge("path",         "?new") -> "path?new"     */
1766       /* uri_merge("path?foo",     "?new") -> "path?new"     */
1767       /* uri_merge("path?foo#bar", "?new") -> "path?new"     */
1768       /* uri_merge("path#foo",     "?new") -> "path?new"     */
1769       int baselength = end - base;
1770       merge = xmalloc (baselength + linklength + 1);
1771       memcpy (merge, base, baselength);
1772       memcpy (merge + baselength, link, linklength);
1773       merge[baselength + linklength] = '\0';
1774     }
1775   else if (*link == '#')
. . .
4、_____________________------------->
url_has_scheme (const char *url)  意思是如果以scheme格式,开始的话就返回1,如果不要就返回0.
/*这个函数解释了url格式中的skeme,我查资料没有查到*/
5、__________________-------------------->
120 char *
121 xstrdup (char const *string)
122 {      
123   return xmemdup (string, strlen (string) + 1);
124 }   
113 xmemdup (void const *p, size_t s)
114 {
115   return memcpy (xmalloc (s), p, s);
116 }   
/*这是复制一份该字符串的值*/

论坛徽章:
0
96 [报告]
发表于 2011-10-03 10:51 |只看该作者
path_end(base);/* 1、___________-------->base 是url 地址,src/url.c*/
1714 static const char *
1715 path_end (const char *url)
1716 {
1717   enum url_scheme scheme = url_scheme (url); /*检查是哪种格式的传输协议2、______---------->/src/url.c*/
1718   const char *seps;
1719   if (scheme == SCHEME_INVALID)
1720     scheme = SCHEME_HTTP;       /* use http semantics for rel links */
1721   /* +2 to ignore the first two separators ':' and '/' */
1722   seps = init_seps (scheme) + 2;  /*4、_____---------->src/url.c*/
1723   return strpbrk_or_eos (url, seps);  /*5、_____--------->/src/url.c*/
1724 }
2、____________---------->

426 url_scheme (const char *url)
427 {
428   int i;
429     
430   for (i = 0; supported_schemes[i].leading_string; i++)  /*supported_schemes[]中保存协议++++----------------->*/
431     if (0 == strncasecmp (url, supported_schemes[i].leading_string,
432                           strlen (supported_schemes[i].leading_string))) /*strncasecmp就是比较的*/
433       {
434         if (!(supported_schemes[i].flags & scm_disabled)) /*如果初始化成功。*/
435           return (enum url_scheme) i;   /*返回对应的协议格式*/
436         else
437           return SCHEME_INVALID;
438       }
439
440   return SCHEME_INVALID;
441 }
++++++++++------------>
60 struct scheme_data
  61 {
  62   /* Short name of the scheme, such as "http" or "ftp". */
  63   const char *name;
  64   /* Leading string that identifies the scheme, such as "https://". */
  65   const char *leading_string;
  66   /* 如果HTTPS端口没有被指定,那么就是那个80. */
  67   int default_port;   
  68   /* Various flags. */
  69   int flags;
  70 };
  53 enum {
  54   scm_disabled = 1,             /* for https when OpenSSL fails to init. */
  55   scm_has_params = 2,           /* whether scheme has ;params */
  56   scm_has_query = 4,            /* whether scheme has ?query */
  57   scm_has_fragment = 8          /* whether scheme has #fragment */
  58 };


73 static struct scheme_data supported_schemes[] =
  74 {
  75   { "http",     "http://",  DEFAULT_HTTP_PORT,  scm_has_query|scm_has_fragment },
  76 #ifdef HAVE_SSL
  77   { "https",    "https://", DEFAULT_HTTPS_PORT, scm_has_query|scm_has_fragment },
  78 #endif
  79   { "ftp",      "ftp://",   DEFAULT_FTP_PORT,   scm_has_params|scm_has_fragment },
  80
  81   /* SCHEME_INVALID */
  82   { NULL,       NULL,       -1,                 0 }
  83 };
  84

如果你看到这里的话应该就明白了*/
4、____--------------->
620 static const char *
621 init_seps (enum url_scheme scheme)
622 {
623   static char seps[8] = ":/";
624   char *p = seps + 2;
625   int flags = supported_schemes[scheme].flags;
626
627   if (flags & scm_has_params)
628     *p++ = ';';
629   if (flags & scm_has_query)
630     *p++ = '?';
631   if (flags & scm_has_fragment)
632     *p++ = '#';
633   *p = '\0';            /*根据上述的flags代表的属性来赋值*/
634   return seps;
635 }
5、________________------------>
596 strpbrk_or_eos (const char *s, const char *accept)
597 {
598   char *p = strpbrk (s, accept);  /*函数的用途:在源字符串(source-string)中找出最先含有搜索字符串(searching-string)中的任一字符的位置并返回,若找不到则返回空指针。 */
599   if (!p)
600     p = strchr (s, '\0');
601   return p;
602 }
<------------------________________
返回到is_robot_txt_url()
{
. . . .
xfree(robots_url); /*释放的分配的那部分空间*/

<------------------_____________

到 test_is_robots_txt_url()]

  assert()
}
分析此函数完毕*/

论坛徽章:
0
97 [报告]
发表于 2011-10-03 13:02 |只看该作者
本帖最后由 duanjigang 于 2011-10-03 13:37 编辑

先回答一个朋友的问题

你好.国庆快乐
想问一下,对于axel中,下载一个文件,在程序中是以多个连接来共同达到下载的吗?
你说的每个连接是指什么?
多连接下载切割文件又是什么?
axel.c后面怎么又冒出一个主select用来下载文件?"为每个连接创建一个线程,这个线程只用于连接ftp或者http
服务器,而不做数据下载,因为Axel是用主线程select做下载的"
还要后面的下载主函数

这个axel在下载一个文件时,具体是怎么一个动作?
谢谢


axel“下载文件的过程”是这样的,使用多个网络连接而不是多线程,只不过,在查找镜像文件后,获取各个镜像站点的访问速度时,采用的是多线程。
也就是说:比如,找到10个镜像站点,然后打开10个线程,每个独立的去访问一个镜像站点,获取到每个站点的响应时间。也就是所谓的速度,而没有实际下载文件的数据。

然后在文件下载的实际动作开始的时候,axel_start函数通过多线程调用setup_thread来创建到多个下载源的网络连接。这些多线程负责尝试建立到不同站点的网络连接,也包括重复尝试连接。
每个连接成功的线程都会为这个线程对应的连接返回一个socket描述符。而主线程会创建好一个文件,比如10M,创建一个10M的文件,然后又假如5个线程创建了连接,也就是用5个
连接来下载,每个文件下载的范围为0-2M,2-4M,4-6M,6-8M,8-10M.这些下载范围都会在多线程连接服务器时告知http服务器。

然后主线程要做的就是使用这些socket描述符,采用select的方式,从各个连接读取数据,写入文件对应的偏移位置。当所有连接的数据都下载完成后,整个文件完成。

不知道说清楚没有?呵呵

顺手画了个图,应该更清晰些了吧:wink:

论坛徽章:
0
98 [报告]
发表于 2011-10-03 21:56 |只看该作者
本帖最后由 duanjigang 于 2011-10-03 22:00 编辑

看看axel对象的创建过程,也就是axel_new被调用的方式:

针对:1查找镜像2不查找,单独一个URL 3 不查找,多个URL地址,不同情况时,axel_new的调用方式

  1. //如果设置查找镜像服务器的话
  2.         if( do_search )
  3.         {
  4.                 //查找多少个镜像服务器
  5.                 search = malloc( sizeof( search_t ) * ( conf->search_amount + 1 ) );
  6.                 memset( search, 0, sizeof( search_t ) * ( conf->search_amount + 1 ) );
  7.                 search[0].conf = conf;
  8.                 if( conf->verbose )
  9.                         printf( _("Doing search...\n") );
  10.                 //初始化查找镜像服务器列表,把查找到的文件资源存入列表中
  11.                 i = search_makelist( search, s );
  12.                 if( i < 0 )
  13.                 {
  14.                         fprintf( stderr, _("File not found\n" ) );
  15.                         return( 1 );
  16.                 }
  17.                 if( conf->verbose )
  18.                         printf( _("Testing speeds, this can take a while...\n") );
  19.                 //开始测速,其实就是看谁返回快
  20.                 j = search_getspeeds( search, i );
  21.                 //速度排序,按照时间由大到小排列,也就是速度由小到大排列
  22.                 search_sortlist( search, i );
  23.                 //打印资源列表
  24.                 if( conf->verbose )
  25.                 {
  26.                         printf( _("%i usable servers found, will use these URLs:\n"), j );
  27.                         j = min( j, conf->search_top );
  28.                         printf( "%-60s %15s\n", "URL", "Speed" );
  29.                         for( i = 0; i < j; i ++ )
  30.                                 printf( "%-70.70s %5i\n", search[i].url, search[i].speed );
  31.                         printf( "\n" );
  32.                 }
  33.                 //使用查找的结果创建axel对象列表
  34.                 axel = axel_new( conf, j, search );
  35.                 free( search );
  36.                 if( axel->ready == -1 )
  37.                 {
  38.                         print_messages( axel );
  39.                         axel_close( axel );
  40.                         return( 1 );
  41.                 }
  42.         }//不查找镜像服务器,
  43.         //就一个下载URL
  44.         else if( argc - optind == 1 )
  45.         {
  46.                 axel = axel_new( conf, 0, s );
  47.                 if( axel->ready == -1 )
  48.                 {
  49.                         print_messages( axel );
  50.                         axel_close( axel );
  51.                         return( 1 );
  52.                 }
  53.         }
  54.         else //直接指定了URL,多个URL,比如 axel -n 10 www.126.com/1.txt ww.163.com/1.txt www.sohu.com/1.txt
  55.         {
  56.                 search = malloc( sizeof( search_t ) * ( argc - optind ) );
  57.                 memset( search, 0, sizeof( search_t ) * ( argc - optind ) );
  58.                 for( i = 0; i < ( argc - optind ); i ++ )
  59.                         strncpy( search[i].url, argv[optind+i], MAX_STRING );
  60.                 //针对这一批url创建axel对象
  61.                 axel = axel_new( conf, argc - optind, search );
  62.                 free( search );
  63.                 if( axel->ready == -1 )
  64.                 {
  65.                         print_messages( axel );
  66.                         axel_close( axel );
  67.                         return( 1 );
  68.                 }
  69.         }
复制代码
注意optind和axel_new函数第二个参数的关系
而axel_new做的主要事情就是申请axel_t对象,初始化结构体成员,初始化到服务器的网络连接,获取文件信息

论坛徽章:
0
99 [报告]
发表于 2011-10-03 22:00 |只看该作者
好活动,支持下。。。

论坛徽章:
0
100 [报告]
发表于 2011-10-03 22:22 |只看该作者
本帖最后由 duanjigang 于 2011-10-03 22:51 编辑

axel_new之后,就是axel_open过程了。
axel_open主要是打开本地文件,用于下载存储,如果多个连接的话,进行文件切分:wink:

axel_open和axel_divide

  1. int axel_open( axel_t *axel )
  2. {
  3.         int i, fd;
  4.         long long int j;
  5.        
  6.         if( axel->conf->verbose > 0 )
  7.                 axel_message( axel, _("Opening output file %s"), axel->filename );
  8.         snprintf( buffer, MAX_STRING, "%s.st", axel->filename );
  9.        
  10.         axel->outfd = -1;
  11.        
  12.         /* Check whether server knows about RESTart and switch back to
  13.            single connection download if necessary                        */
  14.        
  15.         //服务器不支持文件片段下载,这样的话,只能用一个连接去老老实实下载了
  16.         if( !axel->conn[0].supported )
  17.         {
  18.                 axel_message( axel, _("Server unsupported, "
  19.                         "starting from scratch with one connection.") );
  20.                 axel->conf->num_connections = 1;//修改连接数
  21.                 axel->conn = realloc( axel->conn, sizeof( conn_t ) ); //只申请一个节点
  22.                 axel_divide( axel );//分割文件
  23.         }
  24.         //支持分片下载,如果状态文件已经存在的话,尝试从状态文件中读取每个连接的状态
  25.         //当前已经下载了多少
  26.         else if( ( fd = open( buffer, O_RDONLY ) ) != -1 )
  27.         {
  28.                 //读取连接数
  29.                 read( fd, &axel->conf->num_connections, sizeof( axel->conf->num_connections ) );
  30.                 //申请资源
  31.                 axel->conn = realloc( axel->conn, sizeof( conn_t ) * axel->conf->num_connections );
  32.                 memset( axel->conn + 1, 0, sizeof( conn_t ) * ( axel->conf->num_connections - 1 ) );
  33.                 //拆分文件
  34.                 axel_divide( axel );
  35.                 //读取已经下载的字节数
  36.                 read( fd, &axel->bytes_done, sizeof( axel->bytes_done ) );
  37.                 //读取每个连接当前下载的位置
  38.                 for( i = 0; i < axel->conf->num_connections; i ++ )
  39.                         read( fd, &axel->conn[i].currentbyte, sizeof( axel->conn[i].currentbyte ) );

  40.                 axel_message( axel, _("State file found: %lld bytes downloaded, %lld to go."),
  41.                         axel->bytes_done, axel->size - axel->bytes_done );
  42.                
  43.                 close( fd );
  44.                 //打开或者创建数据文件       
  45.                 if( ( axel->outfd = open( axel->filename, O_WRONLY, 0666 ) ) == -1 )
  46.                 {
  47.                         axel_message( axel, _("Error opening local file") );
  48.                         return( 0 );
  49.                 }
  50.         }

  51.         /* If outfd == -1 we have to start from scrath now                */
  52.         //重新开始
  53.         if( axel->outfd == -1 )
  54.         {
  55.                 //先拆分文件
  56.                 axel_divide( axel );
  57.                
  58.                 if( ( axel->outfd = open( axel->filename, O_CREAT | O_WRONLY, 0666 ) ) == -1 )
  59.                 {
  60.                         axel_message( axel, _("Error opening local file") );
  61.                         return( 0 );
  62.                 }
  63.                
  64.                 /* And check whether the filesystem can handle seeks to
  65.                    past-EOF areas.. Speeds things up. :) AFAIK this
  66.                    should just not happen:                                */
  67.                 //如果是多连接下载,检测在空文件中,系统是否支持能够seek到一个EOF的位置
  68.                 //也就是测试是否支持空洞文件,不支持的话,把整个文件都填成0,这样保证每个连接都能够在自己该写入的地方写入数据
  69.                 if( lseek( axel->outfd, axel->size, SEEK_SET ) == -1 && axel->conf->num_connections > 1 )
  70.                 {
  71.                         /* But if the OS/fs does not allow to seek behind
  72.                            EOF, we have to fill the file with zeroes before
  73.                            starting. Slow..                                */
  74.                         axel_message( axel, _("Crappy filesystem/OS.. Working around. :-(") );
  75.                         lseek( axel->outfd, 0, SEEK_SET );
  76.                         memset( buffer, 0, axel->conf->buffer_size );
  77.                         j = axel->size;
  78.                         //循环填充文件
  79.                         while( j > 0 )
  80.                         {
  81.                                 write( axel->outfd, buffer, min( j, axel->conf->buffer_size ) );
  82.                                 j -= axel->conf->buffer_size;
  83.                         }
  84.                 }
  85.         }
  86.        
  87.         return( 1 );
  88. }
复制代码
axel_divide

  1. static void axel_divide( axel_t *axel )
  2. {
  3.         int i;
  4.        
  5.         //第一个连接的当前位置
  6.         axel->conn[0].currentbyte = 0;
  7.         //该写入的最后一个字节位置
  8.         axel->conn[0].lastbyte = axel->size / axel->conf->num_connections - 1;
  9.         //计算别的连接的开始位置和结束位置
  10.         for( i = 1; i < axel->conf->num_connections; i ++ )
  11.         {
  12. #ifdef DEBUG
  13.                 printf( "Downloading %lld-%lld using conn. %i\n", axel->conn[i-1].currentbyte, axel->conn[i-1].lastbyte, i - 1 );
  14. #endif
  15.                 axel->conn[i].currentbyte = axel->conn[i-1].lastbyte + 1;
  16.                 axel->conn[i].lastbyte = axel->conn[i].currentbyte + axel->size / axel->conf->num_connections;
  17.         }
  18.         axel->conn[axel->conf->num_connections-1].lastbyte = axel->size - 1;
  19. #ifdef DEBUG
  20.         printf( "Downloading %lld-%lld using conn. %i\n", axel->conn[i-1].currentbyte, axel->conn[i-1].lastbyte, i - 1 );
  21. #endif
  22. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP