免费注册 查看新帖 |

Chinaunix

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

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

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

:wink: 开始设置参数了!
分析initialize();

  1. {
  2. 591 {
  3. 592   char *file, *env_sysrc;
  4. 593   bool ok = true;
  5. 601 #ifdef SYSTEM_WGETRC
  6. 602   else if (file_exists_p (SYSTEM_WGETRC)) /*  1、________------>判断文件是否存在,如果存在,就去读取里面内容作判断*/
  7. 603     ok &= run_wgetrc (SYSTEM_WGETRC);
  8. 604 #endif
  9. 607   if (! ok)
  10. 608     {
  11. 609       fprintf (stderr, _()); /*打印出错误*/
  12. 615    file = wgetrc_file_name ();  /*这里是如果存在,就从新写2、________---------->*/

  13. 629     ok &= run_wgetrc (file);
复制代码

  1. 1、________------------->
  2. 538 file_exists_p (const char *filename)
  3. 539 {     
  4. 540 #ifdef HAVE_ACCESS
  5. 541   return access (filename, F_OK) >= 0; /*如果已经访问过了,就判断是否还在这个是系统调用
  6. */
  7. 542 #else
  8. 543   struct_stat buf;
  9. 544   return stat (filename, &buf) >= 0;  /*这个是读取文件状态*/
  10. 545 #endif
  11. 546 }
复制代码

  1. 2、___________--------->
  2. 478 char *
  3. 479 wgetrc_file_name (void)
  4. 480 {
  5. 481   char *file = wgetrc_env_file_name (); 3、_____----->/*根据环境变量WGETRC获得文件*/
  6. 482   if (file && *file)
  7. 483     return file;
  8. 484
  9. 485   file = wgetrc_user_file_name (); /*4、_____----->这里是检查~home/.wgetrc文件,如果有就返回此路径*/
复制代码

  1. 3、_________________------>
  2. 428 char *
  3. 429 wgetrc_env_file_name (void)
  4. 430 {
  5. 431   char *env = getenv ("WGETRC"); /*   env是指向此环境变量的指针 ,我理解的就是目录*/
  6. 432   if (env && *env)
  7. 433     {
  8. 434       if (!file_exists_p (env)) /*如果有WGETRC存在,但是文件却不存在,那么就直接退出*/
  9. 435         {
  10. 436           fprintf (stderr, _("%s: WGETRC points to %s, which does't exist.\n"),
  11. 437                    exec_name, env);
  12. 438           exit (1);
  13. 439         }
  14. 440       return xstrdup (env);  /*如果文件存在,就在此env地址从写环境变量的值*/
  15. 441     }
  16. 442   return NULL;  /*如果没有此环境变量,或者指向的字符串是NULL。那么返回NULL。
  17. 443 }
复制代码
4、______________----------->

  1. 447 char *
  2. 448 wgetrc_user_file_name (void)
  3. 449 {
  4. 450   char *home;
  5. 451   char *file = NULL;
  6. 452   /* If that failed, try $HOME/.wgetrc (or equivalent).  */
  7. 453
  8. 454 #ifdef __VMS         /*vms格式下的路径名*/
  9. 455   file = "SYS$LOGIN:.wgetrc";
  10. 456 #else /* def __VMS */
  11. 457   home = home_dir ();  /*这是获得home的环境变量值*/
  12. 458   if (home)
  13. 459     file = aprintf ("%s/.wgetrc", home); /*一种打印方式。*/
  14. 460   xfree_null (home);  
  15. 461 #endif /* def __VMS [else] */
  16. 462
  17. 463   if (!file)
  18. 464     return NULL;
  19. 465   if (!file_exists_p (file))
  20. 466     {
  21. 467       xfree (file);
  22. 468       return NULL;
  23. 469     }
  24. 470   return file; /*返回文件名*/
  25. 471 }
  26. 472
复制代码
<-----------________________

  1. 从initialize()返回,又是刚才的根据用户输入进行初始化*/
  2. while ((ret = getopt_long (argc, argv,  short_options, long_options, &longindex)) != -1)
  3. 965       if (longindex == -1)  /*如果此值没有变只有找到一个相匹配的长选项才会改变此longindex的值。如果返回?这个字符说明说明长选项或者 没有参数 短选项不为:*/
  4. 966         {
  5. 967           if (ret == '?')  /*此时返回为?那么就--help*/
  6. 968             {
  7. 969               print_usage (0);
  8. 970               printf ("\n");
  9. 971               printf (_("Try `%s --help' for more options.\n"), exec_name     );
  10. 972               exit (2);
  11. 973             }
  12. 974           /* Find the short option character in the mapping.  */
  13. 975           longindex = optmap[ret - 32]; /*找到 /*找到相应的长选项*/
  14. 976         }
  15. 977       val = long_options[longindex].val; /*根据检索到longindex来获得val的值*/
  16. 982       opt = &option_data[val & ~BOOLEAN_NEG_MARKER]; /*获得那个option_data数组中对应元素*/  
  17. 983       switch (opt->type) /*根据cmdline_option类型,用optarg来设置相应修改opt->data*/
  18. 984         {
  19. 985         case OPT_VALUE:
  20. 986          setoptval (opt->data, optarg, opt->long_name); 5、________------->
  21. 987           break;
  22. 988         case OPT_BOOLEAN:
  23. 989           if (optarg)
  24. . . . . .
  25. }
复制代码

  1. 5、____________------------->
  2. 781 void
  3. 782 setoptval (const char *com, const char *val, const char *optname)
  4. 783 {     
  5. 784   /* Prepend "--" to OPTNAME. */  
  6. 785   char *dd_optname = (char *) alloca (2 + strlen (optname) + 1); /*设置成--optname*/
  7. 786   dd_optname[0] = '-';
  8. 787   dd_optname[1] = '-';
  9. 788   strcpy (dd_optname + 2, optname);
  10. 789
  11. 790   assert (val != NULL);
  12. 791   if (!setval_internal (command_by_name (com), dd_optname, val)) 检查是否有命令错误,或者参数,并且最后一步是运行此命令*/
  13. 792     exit (2);
  14. 793 }
  15. 7、______------------->
  16. 733 setval_internal (int comind, const char *com, const char *val)
  17. 734 {
  18. 735   assert (0 <= comind && ((size_t) comind) < countof (commands));
  19. 736   DEBUGP (("Setting %s (%s) to %s\n", com, commands[comind].name, val));
  20. 737   return commands[comind].action (com, val, commands[comind].place); /*最后一步是运行命令*/
  21. 738 }
  22. 例如:这里是com是 accept,commands[comind].place 这里是  &opt.accepts, val是参数*/
复制代码

  1. 调用的是rpl
  2. 29 #undef accept

  3. 32 rpl_accept (int fd, struct sockaddr *addr, socklen_t *addrlen)
  4. 33 {
  5. 34   SOCKET fh = accept (FD_TO_SOCKET (fd), addr, addrlen); /*这是接受网络请求的函数系统调用来了!*/
  6. 35   if (fh == INVALID_SOCKET)  /*在linux下是不可能失败的*/
  7. 36     {
  8. 37       set_winsock_errno (); /*如果是无效的sock文件,那么就返回-1。*/
  9. 38       return -1;
  10. 39     }
  11. 40   else
  12. 41     return SOCKET_TO_FD (fh); /*否则就将改变文件的属性,*/
  13. 42 }  
  14. 29 #define SOCKET_TO_FD(fh)   (_open_osfhandle ((long) (fh), O_RDWR | O_BINAR    Y))
  15. /*这里是windows系统调用函数*/
复制代码

评分

参与人数 1可用积分 +6 收起 理由
dreamice + 6 辛苦了!

查看全部评分

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
162 [报告]
发表于 2011-10-12 08:27 |只看该作者
回复 161# wangzhen11aaa


    兄弟继续,辛苦了!

论坛徽章:
0
163 [报告]
发表于 2011-10-12 09:58 |只看该作者
本帖最后由 duanjigang 于 2011-10-12 10:01 编辑
回复  duanjigang 从conn->fd 中每次读入一个字节,如果是'\n'就停止.然后再for循环中if( conn->message ==  ...
seufy88 发表于 2011-10-11 18:01



    第一点:

      我们能够看到代码段

  1. if( ( r + 10 ) >= size )
  2.                         {
  3.                                 size += MAX_STRING;
  4.                                 conn->message = realloc( conn->message, size );
  5.                         }
复制代码
代码的意思是说,当缓冲区还有不足10个字节的空间时,就重新申请更大空间。
因此,即便最后一个字符为 '\n',  也就是说

  1. message[r] = '\n'
复制代码
时,访问  message[r+4] 是不会越界的。当然   message [r+15] 就可能越界了。


第二点:
理解这段代码需要我们了解 FTP 协议的格式。

每当你键入一个字符串(或者命令) 到 FTP 服务器时(注意,这里是一定要发送到服务器端的,无效的命令会在客户端过滤掉),返回信息的最后一行必定是一个3位的整数(CODE) 然后是空格,然后是文本字符串。

因此对于单独一行的返回值,分析代码,我们知道axel很容易就能解析到的。
另外,有些命令,在最后两行是有前后逻辑关系的,很简单的例子就是, CODE 在两行之间是相同的。
比如dir命令,下面是一个例子:

  1. ftp> dir
  2. 227 Entering Passive Mode (10,32,102,34,98,92)
  3. 150 Accepted data connection
  4. drwxr-xr-x   12 504        ftpgroup         4096 Sep 14 10:08 .
  5. drwxr-xr-x   12 504        ftpgroup         4096 Sep 14 10:08 ..
  6. drwxr-xr-x    2 504        ftpgroup         4096 Sep 13 17:36 ISOs
  7. drwxr-xr-x    7 504        ftpgroup         4096 Sep 14 10:08 LATEST
  8. drwx------    2 504        ftpgroup        16384 Aug 15 19:29 lost+found
  9. drwxr-xr-x   16 504        ftpgroup         4096 Jan 30 12:51 ?ヨ韩?
  10. drwxr-xr-x    3 504        ftpgroup         4096 Jan 30 12:55 ?ㄦ极
  11. drwxr-xr-x    5 504        ftpgroup         4096 Jan 30 13:05 瀛??
  12. drwxr-xr-x   28 504        ftpgroup         4096 Sep 14 09:40 ?靛奖
  13. drwxr-xr-x    6 504        ftpgroup         4096 Jan 30 13:51 ?佃??
  14. drwxr-xr-x   14 504        ftpgroup         4096 Jan 30 14:01 ?充?
  15. drwxr-xr-x    3 504        ftpgroup         4096 Jan 30 14:02 ?充?瑙.?
  16. 226-Options: -a -l
  17. 226 12 matches total
复制代码
能看到后两行的内容,开头都是整数 226, 唯一不同的是结束行的226 和后面的字符串之间有空格。

看看axel的代码是怎么解析的。


首先代码段

  1. while( conn->message[r-1] != '\n' );
  2.                 conn->message[r] = 0;
  3.                 sscanf( conn->message, "%i", &conn->status );
  4.                 if( conn->message[3] == ' ' )
  5.                         complete = 1;
  6.                 else
  7.                         complete = 0;
复制代码
对于返回码 227 和 150 是肯定能解析到的。

然后最后两行,当它解析到第一个 226 时 后面不是空格,因此 complete 为 0

然后在代码段

  1. if( conn->message[i+4] == ' ' )
  2.                         {
  3.                                 j = -1;
  4.                                 sscanf( &conn->message[i+1], "%3i", &j );
  5.                                 if( j == conn->status )
  6.                                         complete = 1;
  7.                         }
复制代码
当它走到倒数第二行时,这个条件正好符合,而且解析出来的 j 为 226
跟原来保存的 conn->status 一致,这时 complete 修改为 1
然后当解析到最后一行的 \n 时,
complete 已经为 1 了,直接修改为 2, 退出,表示结束。

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


    最里面的do-while每次只读入一行,接着就执行后面的for循环了,此时message[]里只存有一行,即使size够,但访问i+4的内容是不确定的
227 Entering Passive Mode (10,32,102,34,98,92)
读入上面第一行后,message[3]是空格,满足条件,complete就会被设为1,在接下来的for中就会直接break,同时最外面的do-while也会stop
ftp服务器返回的其他行完全没有机会用到并分析呀

论坛徽章:
0
165 [报告]
发表于 2011-10-12 11:32 |只看该作者
本帖最后由 duanjigang 于 2011-10-12 11:43 编辑
回复  duanjigang


    最里面的do-while每次只读入一行,接着就执行后面的for循环了,此时message[]里只 ...
seufy88 发表于 2011-10-12 11:30



    是啊,呵呵,因为这个 ftp_wait就是等待这个返回码的:wink:
确实在dir命令中,是会在前面返回的。
这样的,如果是 “整数 字符串”这种方式的话。这行肯定就返回了
而且在 for循环中。complete已经为1了,直接就修改为2,break了,不会再访问 message[r+4]了

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

回复 165# duanjigang

再问一下,如果第一行返回的不是"整数 字符串"返回的头两行如下
drwxr-xr-x   12 504        ftpgroup         4096 Sep 14 10:08
227 Entering Passive Mode (10,32,102,34,98,92)

由于第一行没有数字开头,所以status值不变(应该是初始化的0)
  1. sscanf( conn->message, "%i", &conn->status );
复制代码
由于complete不为2,再次回到do-while中,再次读入下一行,
  1. while( conn->message[r-1] != '\n' );
  2.                 conn->message[r] = 0;
复制代码
读入第二行时,这一行的第一个字节就会覆盖掉message[r]='\0'这一字节
第二行读完后.message[]的内容就是
drwxr-xr-x   12 504        ftpgroup         4096 Sep 14 10:08\n227 Entering Passive Mode (10,32,102,34,98,92)\n\0
只要第一行没满足
  1. if( conn->message[3] == ' ' )
复制代码
那接下来的都不会满足上一条件了.也就是说直接进入for循环中的第二个if语句

j应该是第二行开头的数字227,但status应该一直是最初的值,所以最后大do-while怎么退出呢?现在只有j==status的情况下才会退出,但这种情况有吗?这段代码没明白
  1. j == conn->status
复制代码
这个条件好像不满足
  1. if( conn->message[i+4] == ' ' )
  2.                         {
  3.                                 j = -1;
  4.                                 sscanf( &conn->message[i+1], "%3i", &j );
  5.                                 if( j == conn->status )
  6.                                         complete = 1;
  7.                         }
复制代码

论坛徽章:
0
167 [报告]
发表于 2011-10-12 12:46 |只看该作者
回复 162# dreamice
努力啊!还有很多。。。。。。

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
168 [报告]
发表于 2011-10-12 13:25 |只看该作者
回复 23# duanjigang
对函数search_getspeeds的实现有一个问题。
  1. while(done < count)
复制代码
作者通过while循环来判断是否所有的线程已经推出。那为什么不用更简洁的方法pthread_join来判断是否所有的线程都退出。
我认为这样会更加简洁吧。

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

下面就是运行修改default的设置了。

  1. 983       switch (opt->type)
  2. 984         {
  3. 985         case OPT_VALUE:  /*如果得到的是含有参数的选项*/

  4. 986           setoptval (opt->data, optarg, opt->long_name); /*1、______--------->
  5. 987           break;
复制代码

  1. 781 void
  2. 782 setoptval (const char *com, const char *val, const char *optname)/*com就是命令了,val是选项参数,optname就是长选项的名字*/
  3. 783 {
  4. 784   /* Prepend "--" to OPTNAME. */
  5. 785   char *dd_optname = (char *) alloca (2 + strlen (optname) + 1);
  6. 786   dd_optname[0] = '-';
  7. 787   dd_optname[1] = '-';
  8. 788   strcpy (dd_optname + 2, optname);  /*前面几个是在optname前面加上 "--"符号*/
  9. 789  
  10. 790   assert (val != NULL);
  11. 791   if (!setval_internal (command_by_name (com), dd_optname, val))/*2、_______----->重要的函数在这里*/
  12. 792     exit (2);
  13. 793 }
复制代码

  1. /*这是折半法查找对应项的索引值。就是commands[]中的数组下标,找到返回此下标,如果没有就返回  -1 。*/
  2. 274 static int
  3. 275 command_by_name (const char *cmdname)
  4. 276 {
  5. 277   /* Use binary search for speed.  Wget has ~100 commands, which
  6. 278      guarantees a worst case performance of 7 string comparisons.  */
  7. 279   int lo = 0, hi = countof (commands) - 1;
  8. 280
  9. 281   while (lo <= hi)
  10. 282     {
  11. 283       int mid = (lo + hi) >> 1;
  12. 284       int cmp = strcasecmp (cmdname, commands[mid].name);
  13. 285       if (cmp < 0)
  14. 286         hi = mid - 1;
  15. 287       else if (cmp > 0)
  16. 288         lo = mid + 1;
  17. 289       else
  18. 290         return mid;
  19. 291     }
  20. 292  return -1;
  21. }
  22. [code]
  23. 732 static bool
  24. 733 setval_internal (int comind, const char *com, const char *val) /*
  25. 734 {
  26. 735   assert (0 <= comind && ((size_t) comind) < countof (commands));
  27. 736   DEBUGP (("Setting %s (%s) to %s\n", com, commands[comind].name, val));
  28. 737   return commands[comind].action (com, val, commands[comind].place);/*这里就又一步处理解析过程3、________---------->*/
  29. 738 }
复制代码

  1. commands[comind].action() ,其中有这几中类型:
  2. 117   { "accept",           &opt.accepts,           cmd_vector },
  3. 118   { "addhostdir",       &opt.add_hostdir,       cmd_boolean },
  4. 126   { "backups",          &opt.backups,           cmd_number },
  5. 127   { "base",             &opt.base_href,         cmd_string },
  6. 130   { "cacertificate",    &opt.ca_cert,           cmd_file },
  7. 134   { "cadirectory",      &opt.ca_directory,      cmd_directory },
  8. 135   { "certificate",      &opt.cert_file,         cmd_file },
  9. 136   { "certificatetype",  &opt.cert_type,         cmd_cert_type },
  10. etc*/
  11.                这些都是去改变command[]数组中的place的值*/
  12. 因为类似这里只说一个*/
复制代码

  1. 957 static bool
  2. 958 cmd_vector (const char *com, const char *val, void *place) /*place是指
  3. 959 {
  4. 960   char ***pvec = (char ***)place;
  5. 961   
  6. 962   if (*val)
  7. 963     *pvec = merge_vecs (*pvec, sepstring (val));/sepstring()将参数再次解析成以数粗形式存储的变量4、___------------->*/
复制代码

  1. 1310 char **
  2. 1311 merge_vecs (char **v1, char **v2)
  3. 1312 {   
  4. 1313   int i, j;
  5. 1314   
  6. 1315   if (!v1)
  7. 1316     return v2;
  8. 1317   if (!v2)
  9. 1318     return v1;
  10. 1319   if (!*v2)
  11. 1320     {
  12. 1321       /* To avoid j == 0 */
  13. 1322       xfree (v2);
  14. 1323       return v1; /*如果参数是0的话,那么就采用默认值*/
  15. 1324     }
  16. 1325   /* Count v1.  */
  17. 1326   for (i = 0; v1[i]; i++)
  18. 1327     ;
  19. 1328   /* Count v2.  */
  20. 1329   for (j = 0; v2[j]; j++)
  21. 1330     ;
  22. 1331   /* Reallocate v1.  */
  23. 1332   v1 = xrealloc (v1, (i + j + 1) * sizeof (char **));  
  24. 1333   memcpy (v1 + i, v2, (j + 1) * sizeof (char *));
  25. 1334   xfree (v2);
  26. 1335   return v1;
  27. 1336 }
复制代码
/*这里是改变commands[]数组中 *place的内容,就是改变的当初defaults[]的内容*/

  1. 下面就是一系列的判断,如果出错就打印出来*/
  2. 比如
  3. if(!opt.locale)
  4. opt.locale = find_locale(); /*最终为系统调用*/

  5. 1202   if (opt.ask_passwd)
  6. 1203     {
  7. 1204       opt.passwd = prompt_for_password (); /*接受密码6、________----->*/
  8. 1205
  9. 1206       if (opt.passwd == NULL || opt.passwd[0] == '\0')
  10. 1207         exit (1);
  11. 1208     }
复制代码

  1. 6、________---------->
  2. static char *prompt_for_password(void)
  3. {
  4. . . .
  5. return getpass(""); /*接受函数*/
  6. }
复制代码

  1. 86 char *
  2. 87 getpass (const char *prompt)
  3. 88 {
  4. 89   FILE *tty;
  5. 90   FILE *in, *out;
  6. 91   struct termios s, t;
  7. 92   bool tty_changed = false;
  8. 93   static char *buf;
  9. 94   static size_t bufsize;
  10. 95   ssize_t nread;
  11. 96
  12. 97   /* Try to write to and read from the terminal if we can.
  13. 98      If we can't open the terminal, use stderr and stdin.  */
  14. 99
  15. 100   tty = fopen ("/dev/tty", "w+");
  16. 101   if (tty == NULL)  /*如果可以从终端输入打开终端设备文件,进行输入*/
  17. 102     {
  18. 103       in = stdin;  /*如果没有,那么用标准输入进行输出*/
  19. 104       out = stderr; /*输出文件为stderr*/
  20. 105     }
  21. 106   else
  22. 107     {
  23. 108       /* We do the locking ourselves.  */
  24. 109       __fsetlocking (tty, FSETLOCKING_BYCALLER);
  25. 110
  26. 111       out = in = tty;
  27. 112     }
  28. 113
  29. 114   flockfile (out);
  30. . . . . .  .  /*省略的是对文件进行加锁*/
  31. 133   nread = getline (&buf, &bufsize, in);

复制代码

论坛徽章:
0
170 [报告]
发表于 2011-10-12 14:08 |只看该作者
网络sock初始化

  1. 1213   sock_init();
复制代码

  1. 获得url地址
  2. 1225   url = alloca_array (char *, nurl + 1); /urll长度定义为 1070   nurl = argc - optind; /*前面选项后面的字串长度*/
  3. 1226   for (i = 0; i < nurl; i++, optind++)  /*
  4. 1227     {
  5. 1228       char *rewritten = rewrite_shorthand_url (argv[optind]); 1、_____-------->从新写url地址,也有检查的意思*/
  6. 1229       if (rewritten)
  7. 1230         url[i] = rewritten;
  8. 1231       else
  9. 1232         url[i] = xstrdup (argv[optind]);
  10. 1233     }
  11. 1、_____________----------->
  12. 547 char *
  13. 548 rewrite_shorthand_url (const char *url)
  14. 549 {
  15. 550   const char *p;
  16. 551   char *ret;
  17. 552      
  18. 553   if (url_scheme (url) != SCHEME_INVALID) /*url_scheme()检查是否为支持的格式2、______--->*/
  19. 554     return NULL;
复制代码

  1. url_skeme()函数就是比较使用,比较简单,不说了*/
  2. 425 enum url_scheme
  3. 426 url_scheme (const char *url)
  4. 427 {
  5. 428   int i;
  6. 429
  7. 430   for (i = 0; supported_schemes[i].leading_string; i++)
  8. 431     if (0 == strncasecmp (url, supported_schemes[i].leading_string,
  9. 432                           strlen (supported_schemes[i].leading_string)))
  10. 433       {
  11. 434         if (!(supported_schemes[i].flags & scm_disabled))
  12. 435           return (enum url_scheme) i;
  13. 436         else
  14. 437           return SCHEME_INVALID;
  15. 438       }
  16. 439
  17. 440   return SCHEME_INVALID;
  18. 441 }
复制代码


  1. 73 static struct scheme_data supported_schemes[] =
  2.   74 {
  3.   75   { "http",     "http://",  DEFAULT_HTTP_PORT,  scm_has_query|scm_has_fragm     ent },
  4.   76 #ifdef HAVE_SSL
  5.   77   { "https",    "https://", DEFAULT_HTTPS_PORT, scm_has_query|scm_has_fragm     ent },
  6.   78 #endif
  7.   79   { "ftp",      "ftp://",   DEFAULT_FTP_PORT,   scm_has_params|scm_has_frag     ment },
  8.   80
  9.   81   /* SCHEME_INVALID */
  10.   82   { NULL,       NULL,       -1,                 0 }
  11.   83 };
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP