LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 847|回复: 2

C语言写的批量下载程序for linux

[复制链接]
发表于 2005-4-10 14:23:50 | 显示全部楼层 |阅读模式
本程序使用wget下载一批量的URL,最多进程数为5个.
用法:
  1. mdown http://www.abc.com/track/track[001-2].mp3
复制代码

将下载:
http://www.abc.com/track/track001.mp3
http://www.abc.com/track/track002.mp3
等文件,GPL发布,希望对你有用.

对fork(), execve()和信号没懂的朋友也是一个帮助.

Mdown.c

  1. /* Author: liquid_zigong@www.linuxsir.cn */

  2. #include<stdio.h>
  3. #include<string.h>
  4. #include<stdlib.h>
  5. #include<signal.h>
  6. #include<unistd.h>

  7. /* 最大进程数 */
  8. #define MAXPROC 5                       

  9. /* 下载工具的位置 */
  10. #define PROG "/usr/bin/wget"

  11. /* 临时文件记录名前缀 */
  12. #define TMPPREF "/tmp/.moviedownloader"

  13. void cleanup(void);
  14. void sig_cleanup(int sig);
  15. int usage(int argc, char* argv[]);
  16. int url2file(char* outfile, char *url);
  17. int start_download_proc(char *outfile, int maxproc);
  18. int detail_info(char *outfile);

  19. int main(int argc, char *argv[])
  20. {
  21.     char outfile[80];

  22.     if(argc < 2) {
  23.         usage(argc, argv);
  24.         exit(1);
  25.     }

  26.     /*注册退出时清理函数*/
  27.     atexit(&cleanup);
  28.     signal(SIGINT, &sig_cleanup);
  29.    
  30.     sprintf(outfile, "%s%d", TMPPREF, getpid());

  31.     url2file(outfile, argv[1]);
  32.     detail_info(outfile);
  33.     start_download_proc(outfile, MAXPROC);

  34.     return 0;
  35. }

  36. int usage(int argc, char* argv[])
  37. {
  38.     fprintf(stderr, "%s: url[start-end]\n", argv[0]);
  39.     return 0;
  40. }

  41. /*把转换后的URL写入outfile*/
  42. int url2file(char* outfile, char *url)
  43. {
  44.     char prefix[BUFSIZ], suffix[BUFSIZ], fmt[40], *p;
  45.     FILE *fp;
  46.     int start, end, zerocnt = 0, i;

  47.     fp = fopen(outfile, "w");
  48.     if(!fp) {
  49.         perror("url2file");
  50.         exit(1);
  51.     }
  52.    
  53.     if((p=strchr(url, '[')) == NULL) {
  54.         fclose(fp);
  55.         fprintf(stderr, "Bad URL assigned\n");
  56.         exit(1);
  57.     }
  58.    
  59.     if((p=strchr(p, '-')) == NULL) {
  60.         fclose(fp);
  61.         fprintf(stderr, "Bad URL assigned\n");
  62.         exit(1);
  63.     }
  64.    
  65.     if((p=strchr(p, ']')) == NULL) {
  66.         fclose(fp);
  67.         fprintf(stderr, "Bad URL assigned\n");
  68.         exit(1);
  69.     }

  70.     p = strchr(url, '[');
  71.     p++;
  72.     while(*p == '0') {
  73.         p++;
  74.         zerocnt ++;
  75.     }

  76.     p = strchr(url, '[');
  77.     start = atoi(p+1);
  78.     p = strchr(p, '-');
  79.     end = atoi(p+1);
  80.    
  81.     strncpy(prefix, url, strchr(url, '[') - url);
  82.     p = strchr(strchr(url, '['), ']');

  83.     p++;
  84.     strcpy(suffix, p);

  85.    
  86.     sprintf(fmt, "%%s%%0%dd%%s\n", zerocnt+1);
  87.     for(i = start; i <= end; i++) {
  88.         fprintf(fp, fmt, prefix, i, suffix);
  89.     }
  90.    
  91.     fclose(fp);
  92.     return 1;
  93. }

  94. /*开maxproc个进程同时下载*/
  95. int start_download_proc(char *outfile, int maxproc)
  96. {
  97.     int result;
  98.     int proc = 0;
  99.     pid_t pid;
  100.     FILE *fp, *logger;
  101.     char line[BUFSIZ], *argv[] = {
  102.         PROG,          /* 第一个参数 */
  103.         line,             /* 第二个参数 */
  104.         NULL           /* 这是参数的结束,必须的 */
  105.     };

  106.     if((fp = fopen(outfile, "r")) == NULL) {
  107.         perror("start_download_proc");
  108.         exit(1);
  109.     }
  110.    
  111.     while(fgets(line, sizeof(line), fp) != NULL) {
  112.         /* fgets() 会在字符串后加上个'\n',删掉它 */
  113.         line[strlen(line) - 1] = '\0';

  114.         pid = fork();
  115.         if(pid < 0) {
  116.             perror("fork");
  117.             exit(1);
  118.         }

  119.         if(pid == 0) {
  120.             /* 关闭STDIN_FILENO和STDOUT_FILENO */
  121.             /* 这样就看不到wget终端输出
  122.             close(0);
  123.             close(1);
  124.             /* close(2); */
  125.             
  126.             execve(PROG, argv, NULL);
  127.             abort();
  128.         }

  129.         proc++;
  130.         if(proc == maxproc) {
  131.             wait(&result);
  132.             printf("A download finished\n");
  133.             proc--;
  134.         }
  135.    }

  136.    /*如果还有没下载完的*/
  137.    printf("All task assigned, waiting for children\n");
  138.    while(proc != 0) {
  139.        wait(&result);
  140.        proc --;
  141.    }
  142.    
  143.    printf("All downloads finisned\n");
  144.    return 1;
  145. }

  146. /*用户按下Ctrl-C键时,清理文件*/
  147. void sig_cleanup(int sig)
  148. {
  149.     char filename[20];
  150.     sprintf(filename , "%s%d", TMPPREF, getpid());
  151.     unlink(filename);
  152.     exit(0);
  153. }

  154. /*正常退出时清理文件*/
  155. void cleanup(void)
  156. {
  157.     char filename[20];
  158.     sprintf(filename , "%s%d", TMPPREF, getpid());
  159.     unlink(filename);
  160. }

  161. /*显示下载文件细节*/
  162. int detail_info(char *outfile)
  163. {
  164.     FILE *fp;
  165.     char line[BUFSIZ];
  166.    
  167.     if((fp = fopen(outfile, "r")) == NULL) {
  168.         perror("detail_inf");
  169.         exit(0);
  170.     }
  171.    
  172.     printf("Going to download:\n");
  173.     while(fgets(line, sizeof(line), fp) != NULL) {
  174.        printf("%s", line);
  175.     }

  176.     printf("\n");
  177.     return sleep(1);
  178. }
复制代码
发表于 2005-4-10 17:54:06 | 显示全部楼层
作为编程练习还行
其实干这种事情,最简单的办法是使用脚本语言来编写
可能就那么几行代码
回复 支持 反对

使用道具 举报

发表于 2005-4-10 18:44:12 | 显示全部楼层
我以为是多线程下载呢,以为是全是自己实现的,原来还要exec啊!
不过作为示例,不错啊!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表