免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
1
双子座
日期:2013-11-06 17:18:01
151 [报告]
发表于 2011-10-10 21:50 |只看该作者
回复 136# duanjigang


    哦,还没看到,我想提前问一下,tcp_connect的实现不需要指定local_if(即interfaces)吗,eth0或一个IP地址这样的?那它怎么知道从哪个interface出去连接远端服务器(host)呢?

论坛徽章:
0
152 [报告]
发表于 2011-10-10 22:08 |只看该作者
敬告:
关于我的最后一个分析,由于关系到了ELF文件,系统调用等,如果你读的时候很困难再去看我写的博客会对你从宏观上认识整个过程很有帮助!

论坛徽章:
0
153 [报告]
发表于 2011-10-11 09:21 |只看该作者
回复  duanjigang


    哦,还没看到,我想提前问一下,tcp_connect的实现不需要指定local_if(即interfac ...
seufy88 发表于 2011-10-10 21:50



    这篇文章说的很好:
http://hi.baidu.com/whandsome/bl ... dc45bda50f52da.html

一台电脑可以同时有多个网络连接,如果不绑定指定的IP,系统就会按照默认路由表经过默认的网关进行数据的收发;

    拿一个简单的TCP通信程序来说,服务端需要在指定的端口进行监听,所以必须绑定指定的端口,而客户端创建的socket是连接指定的服务端,创建socket后直接调用connect()函数就可以连接到指定的服务端;系统会根据默认的路由和空闲的端口,让数据从指定的网关和端口出去;如果要从指定的网卡进行通信,可以在客户端创建socket后调用bind()绑定指定的IP和端口,然后在调用connet()连接指定的服务端.

    FTP也一样,都是TCP方式的数据传输,如果需要FTP客户端要指定从哪个网络连接进行测试(即指定从哪个网卡收发数据),可以在创建socket是调用bind()函数对本机的IP进行绑定,无论是内网的IP还是公网的IP,只要绑定本机上的IP就行了!

   还有一点很重要,就是调用bind()时绑定的端口要设为零,即让系统自己随机分配端口;FTP客户端连接服务器进行文件的上传和下载,需要和服务器建立两个通道:控制通道和数据通道.控制通道:传输FTP命令;数据通道:进行数据传输;一共有三个socket:负责命令通道的socket;负责数据传输的socket;建立数据通道时负责监听服务器连接的socket;三个socket在创建后都要绑定指定的网卡的IP,才可以从指定的网卡上进行收发数据.

论坛徽章:
0
154 [报告]
发表于 2011-10-11 09:57 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-10-11 10:00 编辑

回复 152# wangzhen11aaa
前面的进入int 0x80是进入系统调用。
花了好大力气,才知道系统调用外部也是很复杂的!
系统调用是运行在内核空间的,调用通过vdso这个环境。一开始linux装载和系统相关的调用代码(当然不是系统调用的那个整个函数).so文件装载到一个相应的物理页面,由内核分配的。然后将这个.so文件对映设置到辅助向量中,此辅助向量在线程堆栈中,这样线程可以通过访问辅助向量来访问这些调用函数(在别的虚拟地址空间)。就是这样一个过程。vdso就是提供了一个动态加载的环境,在内核中就是直接调用int 0x80这个调用函数也是在另一个空间也是通过辅助向量访问的。关于系统调用过程我就不说了,感兴趣自己去读源代码。

论坛徽章:
0
155 [报告]
发表于 2011-10-11 11:12 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-10-11 15:48 编辑

接着分析:
这段是将刚才那些模糊匹配的结构写入stderr文件.
_IO_flockfile (stderr);它完成的是用本线程对stderr进行加锁,目的是它占用用来输出错误信息给终端。

  1. 563   int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
  2. 564                       ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; /*==++>  #define _IO_FLAGS2_NOTCANCEL 2*/
  3. 565
  4. 566                       __fxprintf (NULL, "%s", buf);1、______________---------------->
  5. 567
  6. 568                       ((_IO_FILE *) stderr)->_flags2 = old_flags2;
  7. 569                       _IO_funlockfile (stderr);  /*解锁,把缓冲区释放*/
  8. 570
  9. 571                       free (buf);
  10. 572                     }
  11. 573                 }
复制代码

  1. 此结构定义在libio/libio.h,               stderr是个io文件。
  2. 271 struct _IO_FILE {
  3.   272   int _flags;           /* High-order word is _IO_MAGIC; rest is flags. */
  4.   273 #define _IO_file_flags _flags /*=======>文件中有定义*/
  5.   274
  6.   275   /* The following pointers correspond to the C++ streambuf protocol. */
  7.   276   /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  8.   277   char* _IO_read_ptr;   /* Current read pointer  */
  9.   278   char* _IO_read_end;   /* End of get area. */
  10.   279   char* _IO_read_base;  /* Start of putback+get area. */
  11.   280   char* _IO_write_base; /* Start of put area. */
  12.   281   char* _IO_write_ptr;  /* Current put pointer. */
  13.   282   char* _IO_write_end;  /* End of put area. */
  14.   283   char* _IO_buf_base;   /* Start of reserve area. */
  15.   284   char* _IO_buf_end;    /* End of reserve area. */
  16.   285   /* The following fields are used to support backing up and undo. */
  17.   286   char *_IO_save_base; /* Pointer to start of non-current get area. */
  18.   287   char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  19.   288   char *_IO_save_end; /* Pointer to end of non-current get area. */
  20.   289
  21.   290   struct _IO_marker *_markers;
  22.   291
  23.   292   struct _IO_FILE *_chain;
  24.   293
  25.   294   int _fileno;
  26.   295 #if 0
  27.   296   int _blksize;
  28.   297 #else
  29.   298   int _flags2;
  30.   299 #endif
  31.   300   _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */
  32.   301
  33.   302 #define __HAVE_COLUMN /* temporary */
  34.   303   /* 1+column number of pbase(); 0 is unknown. */
  35.   304   unsigned short _cur_column;
  36.   305   signed char _vtable_offset;
  37.   306   char _shortbuf[1];
  38.   307
  39.   308   /*  char* _save_gptr;  char* _save_egptr; */
  40.   309
  41.   310   _IO_lock_t *_lock;
  42.   311 #ifdef _IO_USE_OLD_IO_FILE
  43.   312 };
复制代码

  1. 1、_____________-------------------->
  2. 30 __fxprintf (FILE *fp, const char *fmt, ...) /*将数据打印到某个文件中*/
  3.    31 {
  4.    32   if (fp == NULL)
  5.    33     fp = stderr;  /*这里是stderr文件*/
  6.    34
  7.    35   va_list ap;           /*va_list是规定指向一个可变参数的动态指针结构*/
  8.    36   va_start (ap, fmt);    /*初始化为指向第一个元素*/
  9.    37
  10.    38   int res;
  11.    39   if (_IO_fwide (fp, 0) > 0)
  12.    40     {
  13.    41       size_t len = strlen (fmt) + 1;  /*size_t使用 详见博客size_t。*/
  14.    42       wchar_t wfmt[len];                 /*GNU Libc规定wchar_t为32位*/
  15.    43       for (size_t i = 0; i < len; ++i)   
  16.    44         {
  17.    45           assert (isascii (fmt[i]));  /*断言是数组内字符是ascii码*/
  18.    46           wfmt[i] = fmt[i];  /*将其中的值赋给wfmt[i];*/
  19.    47         }
  20.    48       res = __vfwprintf (fp, wfmt, ap); /*写入文件中  外部定义的 extern int __vfwprintf (__FILE *__restrict __s, __const wchar_t *__restrict __format,__gnuc_va_list __arg)*/
  21.    49     }
  22.    50   else
  23.    51     res = INTUSE(_IO_vfprintf) (fp, fmt, ap); /*输入文件*/
  24.    52
  25.    53   va_end (ap);
  26.    54
  27.    55   return res;
  28.    56 }
复制代码

  1. <---------------------_________________
  2. /*如果没有定义libc和libio等就用这种直接写的方式*/
  3. 574 #else
  4. 575               fprintf (stderr,
  5. 576                        _("%s: option '%s' is ambiguous; possibilities:"),
  6. 577                        argv[0], argv[d->optind]);
  7. 578               do
  8. 579                 {
  9. 580                   fprintf (stderr, " '--%s'", ambig_list->p->name);
  10. 581                   ambig_list = ambig_list->next;
  11. 582                 }
  12. 583               while (ambig_list != NULL);
  13. 584
  14. 585               fputc ('\n', stderr);
  15. 586 #endif
  16. 587             }
  17. 588           d->__nextchar += strlen (d->__nextchar); /*nextchar 是指针类型,指向下一个*/
  18. 589           d->optind++;                     /*下个选项*/
  19. 590           d->optopt = 0;              
  20. 591           return '?';  /*返回0*/
  21. 592         }这些是将所有的模糊匹配的都打印出来*/
  22. 594       while (ambig_list != NULL)
  23. 595         {
  24. 596           struct option_list *pn = ambig_list->next;
  25. 597           free (ambig_list);
  26. 598           ambig_list = pn;
  27. 599         }
  28. 整层函数都是返回错误提示的。比如返回?的字符值。如果有参数并且短选项为空,代表没有短选项那么就打印?的字符值否则打印:的字符值。
复制代码

  1. <----------------__________________
  2. 返回到 ,这里将optind等参数根据返回情况从新赋值*/
  3. 1128 _getopt_internal (int argc, char **argv, const char *optstring,
  4. 1129                   const struct option *longopts, int *longind, int long_only,
  5. 1130                   int posixly_correct)
  6. 1131 {
  7. 1132   int result;
  8. 1133
  9. 1134   getopt_data.optind = optind;
  10. 1135   getopt_data.opterr = opterr;
  11. 1136      
  12. 1137   result = _getopt_internal_r (argc, argv, optstring, longopts,
  13. 1138                                longind, long_only, &getopt_data,
  14. 1139                                posixly_correct);
  15. 1140
  16. 1141   optind = getopt_data.optind;
  17. 1142   optarg = getopt_data.optarg;
  18. 1143   optopt = getopt_data.optopt;
  19. 1144
  20. 1145   return result;  /*返回的仍然是上面的那些字符,如果返回的是-1,说明查找中出现了错误*/
  21. }
复制代码

  1. <------------------------_____________________
  2. 927   while ((retconf = getopt_long (argc, argv,
  3. 928                                 short_options, long_options, &longindex)) != -1)
  4. 929     {
  5. 930       int confval;
  6. 931       bool userrc_ret = true;
  7. 932       struct cmdline_option *config_opt;
  8. 933       confval = long_options[longindex].val;
  9. 934       config_opt = &option_data[confval & ~BOOLEAN_NEG_MARKER];
  10. 935       if (strcmp (config_opt->long_name, "config") == 0)
  11. 936         {
  12. 937           userrc_ret &= run_wgetrc (optarg);  /*run_wgetrc记录数据optarg文件中*/3、_____--->
  13. 938           use_userconfig = true;
  14. 939         }
  15. 940       if (!userrc_ret) /*如果返回NULL,说明出错*/
  16. 941         {
  17. 942           printf ("Exiting due to error in %s\n", optarg);
  18. 943           exit (2);
  19. 944         }
  20. 945       else  /*如果没有注册,就直接返回错误*/
  21. 946         break;  
  22. 947     }
复制代码

  1. 3、__________----------------->
  2. 529 bool  
  3. 530 run_wgetrc (const char *file)
  4. 531 {     
  5. 532   FILE *fp;
  6. 533   char *line;
  7. 534   int ln;
  8. 535   int errcnt = 0;
  9. 536      
  10. 537   fp = fopen (file, "r"); 以读的方式打开optarg文件,判断是否为致命错误。
  11. 538   if (!fp)
  12. 539     {     
  13. 540       fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
  14. 541                file, strerror (errno));
  15. 542       return true;                      /* not a fatal error */
  16. 543     }
  17. 544   ln = 1;                       
  18. 545   while ((line = read_whole_line (fp)) != NULL) 
  19. 546     { 
  20. 547       char *com = NULL, *val = NULL;
  21. 548       int comind;
  22. 549
  23. 550       /* Parse the line.  解析行中的参数*/
  24. 551       switch (parse_line (line, &com, &val, &comind)) /*这个函数返回命令和参数*/
  25. 552         {
  26. 553         case line_ok:  
  27. 554           /* If everything is OK, set the value.  */
  28. 555           if (!setval_internal_tilde (comind, com, val))  /*这里是将命令的可接受的模式列表从home开始)组合起来并把他们放入&opt.place指向的地址。
  29. 556             {
  30. 557               fprintf (stderr, _("%s: Error in %s at line %d.\n"),
  31. 558                        exec_name, file, ln);
  32. 559               ++errcnt;
  33. 560             }
  34. 561           break;
  35. 562         case line_syntax_error:  /*其他的错误就打印出来*'/
  36. 563           fprintf (stderr, _("%s: Syntax error in %s at line %d.\n"),
  37. 564                    exec_name, file, ln);
  38. 565           ++errcnt;
  39. 566           break;
  40. 567         case line_unknown_command:
  41. 568           fprintf (stderr, _("%s: Unknown command %s in %s at line %d.\n"),
  42. 569                    exec_name, quote (com), file, ln);
  43. 570           ++errcnt;
  44. 571           break;
  45. 572         case line_empty:
  46. 573           break;
  47. 574         default:
  48. 575           abort ();
  49. 576         }
  50. 577       xfree_null (com); /*释放*/
  51. 578       xfree_null (val);
  52. 579       xfree (line);
  53. 580       ++ln;
  54. 581     }
  55. 582   fclose (fp);
  56. 583
  57. 584   return errcnt == 0;
  58. 585 }
复制代码

论坛徽章:
0
156 [报告]
发表于 2011-10-11 15:36 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-10-11 15:48 编辑

wget可以使用用户设置文件".wgetrc"来读取很多设置,我们这里主要利用这个文件来是设置代理服务器使用者用什么用户登录,那么什么用户主目录下的".wgetrc"文件就起作用。例如,"root"用户如果想使用".wgetrc"来设置代理服务器,"/root/.wgetrc"就起作用。 
http-proxy = 111.111.111.111:8080   
ftp-proxy = 111.111.111.111:8080  
这两行的含义是,代理服务器IP地址为:111.111.111.111,端口号为:8080。第一行指定HTTP协议所使用的代理服务器,第二行指定FTP协议所使用的代理服务器。

/* If the user did not specify a config, read the system wgetrc and ~/.wgetrc.      */
如果注册进去后,用户不识别,那么就读~/.wgetrc文件自己写*/

  1. 950   if (use_userconfig == false)
  2. 951     initialize (); 1、____---------->
复制代码


  1. 1、_________------------>

  2. 589 void
  3. 590 initialize (void)
  4. 591 {
  5. 592   char *file, *env_sysrc;
  6. 593   bool ok = true;
  7. 594
  8. 597   env_sysrc = getenv ("SYSTEM_WGETRC");  /*获得环境变量值*/
  9. 598   if (env_sysrc && file_exists_p (env_sysrc)) /*判断文件是否存在*/
  10. 599     ok &= run_wgetrc (env_sysrc);  /*判断是否为致命的错误*/
  11. 600  601 #ifdef SYSTEM_WGETRC          /*如果存在这个文件*/
  12. 602   else if (file_exists_p (SYSTEM_WGETRC))
  13. 603     ok &= run_wgetrc (SYSTEM_WGETRC);  /*检查此文件中是否有fatal error*/
  14. 604 #endif
  15. 605  
  16. 606 if (! ok)  /*如果返回为0,那么就说明其中有fatal error"*/
  17. 608     {
  18. 609       fprintf (stderr, _("\
  19. 610 Parsing system wgetrc file failed, please check '%s'.           \
  20. 611 Or specify a different file using --config\n"), SYSTEM_WGETRC);
  21. 612       exit (2);  /*直接退出*/
  22. 613     }
  23. 614   /* Override it with your own, if one exists.  */
  24. 615   file = wgetrc_file_name ();  /*如果没有,那么就自己写入文件2、________------>*/
  25. 616   if (!file)
  26. 617     return;
  27. 620 #ifdef SYSTEM_WGETRC
  28. 621   if (!strcmp (file, SYSTEM_WGETRC))
  29. 622     {
  30. 623       fprintf (stderr, _("\
  31. 624 %s: Warning: Both system and user wgetrc point to %s.\n"),
  32. 625                exec_name, quote (file));
  33. 626     }
  34. 627   else
  35. 628 #endif
  36. 629     ok &= run_wgetrc (file);
  37. 630
  38. 632   if (!ok)
  39. 633     exit (2);
  40. 634
  41. 635   xfree (file);
  42. 636   return;
  43. 637 }
复制代码

  1. 2、___________---------------->
  2. 478 char *
  3. 479 wgetrc_file_name (void)
  4. 480 {
  5. 481   char *file = wgetrc_env_file_name (); 3、__________------------>
  6. 482   if (file && *file)
  7. 483     return file;
  8. 484
  9. 485   file = wgetrc_user_file_name ();5、__________-------->/*如果环境变量不存在,就查找在$Home/.wgetrc"返回它的路径如果它存在*/
复制代码

  1. 3、_________------------->
  2. 428 char *
  3. 429 wgetrc_env_file_name (void)
  4. 430 {
  5. 431   char *env = getenv ("WGETRC");  /*找到这个环境变量*/
  6. 432   if (env && *env)
  7. 433     {
  8. 434       if (!file_exists_p (env))  /*如果此文件不存在*/
  9. 435         {
  10. 436           fprintf (stderr, _("%s: WGETRC points to %s, which doesn't exist.\n"),
  11. 437                    exec_name, env);
  12. 438           exit (1);  /*就直接退出*/
  13. 439         }
  14. 440       return xstrdup (env); /*4、__________---------->/*初始化一个等同大小空间,元素为不可修改元素*/
  15. 441     }
  16. 442   return NULL;
  17. 443 }
  18. 4、_________------------>
  19. 112 void *
  20. 113 xmemdup (void const *p, size_t s)
  21. 114 {
  22. 115   return memcpy (xmalloc (s), p, s);
  23. 116 }
  24. 119
  25. 120 char *
  26. 121 xstrdup (char const *string)
  27. 122 {
  28. 123   return xmemdup (string, strlen (string) + 1);
  29. 124 }
复制代码

  1. 5、__________-------------->
  2. 447 char *
  3. 448 wgetrc_user_file_name (void)
  4. 449 {
  5. 450   char *home;
  6. 451   char *file = NULL;  
  7. 452   /* If that failed, try $HOME/.wgetrc (or equivalent).  */
  8. 453
  9. 454 #ifdef __VMS
  10. 455   file = "SYS$LOGIN:.wgetrc";  
  11. 456 #else /* def __VMS */
  12. 457   home = home_dir ();  /*6、____------>
  13. 458   if (home)
  14. 459     file = aprintf ("%s/.wgetrc", home);
  15. 460   xfree_null (home);
  16. 461 #endif /* def __VMS [else] */
  17. 462
  18. 463   if (!file)
  19. 464     return NULL;
  20. 465   if (!file_exists_p (file))
  21. 466     {
  22. 467       xfree (file);
  23. 468       return NULL;
  24. 469     }
  25. 470   return file;
  26. 471 }
复制代码

  1. 6、_________--------->
  2. 368 char *
  3. 369 home_dir (void)
  4. 370 {
  5. 371   static char *buf = NULL;
  6. 372   static char *home, *ret;
  7. 373   int len;
  8. 374
  9. 375   if (!home)  
  10. 376     {
  11. 377       home = getenv ("HOME"); /*获得HOME的环境变量*/
  12. 378       if (!home)
  13. 379         {
  14. 380 #if defined(MSDOS)  /*如果是MSDOS环境是不存在HOME的,此处略去。*/
  15.   381           /* Under MSDOS, if $HOME isn't defined, use the directory where
  16. 382              `wget.exe' resides.  */
  17. 383           const char *_w32_get_argv0 (void); /* in libwatt.a/pcconfig.c */
  18. 384           char *p;
  19. 385
  20. 386           buff = _w32_get_argv0 (); /*这个是在dos环境下的*/
  21. 387
  22. 388           p = strrchr (buf, '/');            /* djgpp */
  23. 389           if (!p)
  24. 390             p = strrchr (buf, '\\');          /* others */
  25.   . . . . .  .
  26. 402 #elif !defined(WINDOWS) /*略去*/
  27. 417   ret = home ? xstrdup (home) : NULL; /*如果home 存在就分配一个存储home的空间*/
  28. 418   if (buf)  
  29. 419     free (buf);
  30. 420
  31. 421   return ret;  /*返回*/
  32. 422 }
复制代码

论坛徽章:
0
157 [报告]
发表于 2011-10-11 16:20 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-10-11 16:30 编辑

每一个长选项基本都对应一个短选项。长选项后面带有参数。

每一个长选项基本都对应一个短选项。长选项后面带有参数。
 -V, --version 显示wget的版本后退出
  -h, --help 打印语法帮助 
 -b, --background 启动后转入后台执行 
 -e, --execute=COMMAND 执行`.wgetrc'格式的命令,wgetrc格式参见/etc/wgetrc或~/.wgetrc  
 ●记录和输入文件:   
-o, --output-file=FILE 把记录写到FILE文件中 
 -a, --append-output=FILE 把记录追加到FILE文件中 
 -d, --debug 打印调试输出 
 -q, --quiet 安静模式(没有输出)
  -v, --verbose 冗长模式(这是缺省设置)  
 -nv, --non-verbose 关掉冗长模式,但不是安静模式 
 -i, --input-file=FILE 下载在FILE文件中出现的URLs  
 -F, --force-html 把输入文件当作HTML格式文件对待 
 -B, --base=URL 将URL作为在-F -i参数指定的文件中出现的相对链接的前缀  
--sslcertfile=FILE 可选客户端证书 
 --sslcertkey=KEYFILE 可选客户端证书的KEYFILE
  --egd-file=FILE 指定EGD socket的文件名 
 ●下载:
  --bind-address=ADDRESS 指定本地使用地址(主机名或IP,当本地有多个IP或名字时使用)  
 -t, --tries=NUMBER 设定最大尝试链接次数(0 表示无限制).  
 -O --output-document=FILE 把文档写到FILE文件中 
 -nc, --no-clobber 不要覆盖存在的文件或使用.#前缀 
 -c, --continue 接着下载没下载完的文件 
 --progress=TYPE 设定进程条标记 
 -N, --timestamping 不要重新下载文件除非比本地文件新
 -S, --server-response 打印服务器的回应 
 --spider 不下载任何东西 
 -T, --timeout=SECONDS 设定响应超时的秒数  
-w, --wait=SECONDS 两次尝试之间间隔SECONDS秒  
--waitretry=SECONDS 在重新链接之间等待1...SECONDS秒  
--random-wait 在下载之间等待0...2*WAIT秒 
 -Y, --proxy=on/off 打开或关闭代理 
 -Q, --quota=NUMBER 设置下载的容量限制 
 --limit-rate=RATE 限定下载输率 
 ●目录:  
 -nd --no-directories 不创建目录 
 -x, --force-directories 强制创建目录 
 -nH, --no-host-directories 不创建主机目录 
 -P, --directory-prefix=PREFIX 将文件保存到目录 PREFIX/...  
 --cut-dirs=NUMBER 忽略 NUMBER层远程目录  
●HTTP 选项:  
 --http-user=USER 设定HTTP用户名为 USER.  
 --http-passwd=PASS 设定http密码为 PASS.  
 -C, --cache=on/off 允许/不允许服务器端的数据缓存 (一般情况下允许).
  -E, --html-extension 将所有text/html文档以.html扩展名保存 
 --ignore-length 忽略 `Content-Length'头域 
 --header=STRING 在headers中插入字符串 STRING  
 --proxy-user=USER 设定代理的用户名为 USER   
--proxy-passwd=PASS 设定代理的密码为 PASS   
--referer=URL 在HTTP请求中包含 `Referer: URL'头
-s, --save-headers 保存HTTP头到文件 
 -U, --user-agent=AGENT 设定代理的名称为 AGENT而不是 Wget/VERSION.  
 --no-http-keep-alive 关闭 HTTP活动链接 (永远链接).   
--cookies=off 不使用 cookies.   
--load-cookies=FILE 在开始会话前从文件 FILE中加载cookie  
 --save-cookies=FILE 在会话结束后将 cookies保存到 FILE文件中 
 ●FTP 选项:   
-nr, --dont-remove-listing 不移走 `.listing'文件 
 -g, --glob=on/off 打开或关闭文件名的 globbing机制 
 --passive-ftp 使用被动传输模式 (缺省值).  
 --active-ftp 使用主动传输模式 
 --retr-symlinks 在递归的时候,将链接指向文件(而不是目录)  
 ●递归下载:  
 -r, --recursive 递归下载--慎用!  
 -l, --level=NUMBER 最大递归深度 (inf 或 0 代表无穷).  
 --delete-after 在现在完毕后局部删除文件 
 -k, --convert-links 转换非相对链接为相对链接 
 -K, --backup-converted 在转换文件X之前,将之备份为 X.orig  
 -m, --mirror 等价于 -r -N -l inf -nr.  
 -p, --page-requisites 下载显示HTML文件的所有图片 
 ●递归下载中的包含和不包含(accept/reject):  
 -A, --accept=LIST 分号分隔的被接受扩展名的列表
  -R, --reject=LIST 分号分隔的不被接受的扩展名的列表 
 -D, --domains=LIST 分号分隔的被接受域的列表
  --exclude-domains=LIST 分号分隔的不被接受的域的列表 
 --follow-ftp 跟踪HTML文档中的FTP链接  
--follow-tags=LIST 分号分隔的被跟踪的HTML标签的列表
  -G, --ignore-tags=LIST 分号分隔的被忽略的HTML标签的列表
  -H, --span-hosts 当递归时转到外部主机  
-L, --relative 仅仅跟踪相对链接  
-I, --include-directories=LIST 允许目录的列表
  -X, --exclude-directories=LIST 不被包含目录的列表  
-np, --no-parent 不要追溯到父目录
1
  
/*OPT_BOOLEAN  类型是指会有是否两个选项,以long_name adjust_extension为例:除了本选项,还有个加前缀的no-adjust-extension选现紧跟在后面*/
/*OPT_VALUE: 类型是指long_name(选项有参数),如果有短选项还会在short_opts数组中加上“:”。*/
其他的选项就是说,如果长选项需要一个参数(required_argument)并且有短选项就在short_opts中加上" : "。
*/
158   {
159     { "accept", 'A', OPT_VALUE, "accept", -1 },
160     { "adjust-extension", 'E', OPT_BOOLEAN, "adjustextension", -1 },
161     { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument },
162     { "ask-password", 0, OPT_BOOLEAN, "askpassword", -1 },
163     { "auth-no-challenge", 0, OPT_BOOLEAN, "authnochallenge", -1 },
164     { "background", 'b', OPT_BOOLEAN, "background", -1 },
165     { "backup-converted", 'K', OPT_BOOLEAN, "backupconverted", -1 },
166     { "backups", 0, OPT_BOOLEAN, "backups", -1 },
167     { "base", 'B', OPT_VALUE, "base", -1 },
168     { "bind-address", 0, OPT_VALUE, "bindaddress", -1 },
169     { IF_SSL ("ca-certificate"), 0, OPT_VALUE, "cacertificate", -1 },
170     { IF_SSL ("ca-directory"), 0, OPT_VALUE, "cadirectory", -1 },
171     { "cache", 0, OPT_BOOLEAN, "cache", -1 },

论坛徽章:
0
158 [报告]
发表于 2011-10-11 17:13 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-10-11 18:30 编辑

wget [options] [URL-list]

wget (-; +;   选项  

可以以这些选项开头,这些是决定排序顺序的,排序顺序见前面几个的分析。



                      这里说一下,这个argv和argc的应用。
                        *   argc:   整数,为传给main()的命令行参数个数。
                            *   argv:   字符串数组。  argv是char **类型,所以它可以指向任何一个选项的字符或者字符串。                       而且是依次指向。这就为后面的分析打下了很好的基础。


这只是说到选项,还没有涉及到URL-list。
总结一下前面的周折,给出一个比较宏观的过程:

首先初始化时间,因为时间很重要:),以后会用到的计时器初始化:

  1. struct ptimer *timer = ptimer_new (); /*通过读取映射到系统空间的硬件时钟值来初始化,时钟方面看博客有linux 计时器*/
复制代码

  1. 895   double start_time = ptimer_measure (timer); /*来矫正真正启动的时间如果出现逝去时间(单调时间小于前面的时间值,就重新设置,返回当前的单调时间值(elapsed)作为开始时间,因为准确*/
复制代码


  1.   /*检查本地的字符集, i18n_initialize ();  
  2. 如果并初始化有些需要调用的二进制文件路径(113   setlocale (LC_ALL, "");
  3. 115   bindtextdomain ("wget", LOCALEDIR);
  4. 116   textdomain ("wget");
  5. */
复制代码

  1. 设置程序名称:
  2. 在VMS上要去掉  dev:[dir]前缀和.EXE后缀
  3. exec_name = vms_basename (argv[0]);
  4. argv[0]是本质*/
复制代码

  1. 默认初始化选项的一些属性,如果你在选项中没有设置属性的话,当然不能没有
  2. 917   defaults ();
复制代码

  1. 这个文件是将cmdline_options类型的option_data[]数组中的所有元素进行分类存放。存放在long_options数组(option类型,存储long_option的名称,有无参数,它对应的标志(OPT_VALUE等),还有个val记录本身是否在1024内,如果在外边那么说明,这是带有no-前缀的,(char 类型只存储段选项和参数)short_options数组,还有optmap[]数组将短长选项对应起来。
  2. 919   init_switches ();
复制代码

  1. 后面花费时间最长的就是这个get_long()函数了
  2. 这个函数是选择长选项和短选项进行匹配,
  3. 出现的情况就是找到了,那么在后面看看是否注册if (strcmp (config_opt->long_name, "config") == 0)
  4. 我查了下,只有一个文件的long_name为config,只会检测这个是否注册成功,这涉及到后面的wgetrc文件的注册。 { "config", 0, OPT_VALUE, "chooseconfig", -1 }
  5. 很多程序在后面都会返回一个"?"的ascii码值。ascii码是127应该是个随意值(i think they make it for fun),所以会进行检查。
  6. 其他的都不用管,因为  bool userrc_ret = true;

复制代码

  1. 查找的过程中,如果找到了相似,我指的是long_name相同,但是参数不同,属性不同啦,都会将错误输出stderr来显示错误
  2.    if (pfound->has_arg)
  3. 610                 d->optarg = nameend + 1;
  4. 如果找到了长选项,然后它还有一个参数,那么就用d->optarg来存储选项后面的参数。在后面将用它作为用户写入.wgetrc文件的内容。
复制代码


  1. 935       if (strcmp (config_opt->long_name, "config") == 0)
  2. 936         {
  3. 937           userrc_ret &= run_wgetrc (optarg);
  4. 938           use_userconfig = true;
  5. 939         }
  6. */
复制代码

  1. 530 run_wgetrc (const char *file) 调用
复制代码

  1. 545   while ((line = read_whole_line (fp)) != NULL) /*读取刚写入optarg文件的每一行进行测试*/
  2. 546     {
  3. 547       char *com = NULL, *val = NULL;
  4. 548       int comind;
  5. 549
  6. 550       /* Parse the line.  */
  7. 551       switch (parse_line (line, &com, &val, &comind)) /*对命令所在选项位置进行匹配,匹配成功就是line_ok,出现错误就打印出来。*/

复制代码

  1. 950   if (use_userconfig == false)
  2. 951     initialize ();
  3. /*这里是如果没有注册进去,在这里才会将use_userconfig = ture;
  4. 读取环境变量,然后找到此文件,进行写!
复制代码

论坛徽章:
1
双子座
日期:2013-11-06 17:18:01
159 [报告]
发表于 2011-10-11 18:01 |只看该作者
本帖最后由 seufy88 于 2011-10-11 23:05 编辑

回复 153# duanjigang
  1. int ftp_wait( ftp_t *conn )
  2. {
  3.         int size = MAX_STRING, r = 0, complete, i, j;
  4.         char *s;
  5.        
  6.         conn->message = realloc( conn->message, size );
  7.        
  8.         do
  9.         {
  10.                 do
  11.                 {
  12.                         r += i = read( conn->fd, conn->message + r, 1 );
  13.                         if( i <= 0 )
  14.                         {
  15.                                 sprintf( conn->message, _("Connection gone.\n") );
  16.                                 return( -1 );
  17.                         }
  18.                         if( ( r + 10 ) >= size )
  19.                         {
  20.                                 size += MAX_STRING;
  21.                                 conn->message = realloc( conn->message, size );
  22.                         }
  23.                 }
  24.                 while( conn->message[r-1] != '\n' );
  25.                 conn->message[r] = 0;
  26.                 sscanf( conn->message, "%i", &conn->status );
  27.                 if( conn->message[3] == ' ' )
  28.                         complete = 1;
  29.                 else
  30.                         complete = 0;
  31.                
  32.                 for( i = 0; conn->message[i]; i ++ ) if( conn->message[i] == '\n' )
  33.                 {
  34.                         if( complete == 1 )
  35.                         {
  36.                                 complete = 2;
  37.                                 break;
  38.                         }
  39.                         if( conn->message[i+4] == ' ' )
  40.                         {
  41.                                 j = -1;
  42.                                 sscanf( &conn->message[i+1], "%3i", &j );
  43.                                 if( j == conn->status )
  44.                                         complete = 1;
  45.                         }
  46.                 }
  47.         }
  48.         while( complete != 2 );
  49. return( conn->status );
复制代码
从conn->fd 中每次读入一个字节,如果是'\n'就停止.然后再for循环中
  1.         if( conn->message[i+4] == ' ' )
复制代码
if( conn->message == '\n' ) 此时的i+4是不是"越界"了?conn->message[]每次读完后只有一个\n,就在最后一个元素
ftp服务器端返回的是220空格<vsftpd 2.3.4>
conn->message[]={................\n}  遍历这个数组,找到空格就结束.如果没有找到空格,就查看i+4是否为空格,对这个有点不明白.

论坛徽章:
0
160 [报告]
发表于 2011-10-11 20:53 |只看该作者
有难度,
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP