查看: 690|回复: 0

[C++资源] C语言写的一个http下载工具

[复制链接]
发表于 2015-4-12 11:30 | 显示全部楼层 |阅读模式
冒烟的左轮 2015-4-12 11:30 690 0 显示全部楼层
配置文件存放在WEB目录中的某些目录,相对路径已知,发现用系统自带的wget工具下载配置文件时,必须要把文件完整下载过来后再去读配置文件,这样感觉有点不灵活,于是自己写了一个HTTP下载工具,这样在获取配置文件内容时比较灵活,可以无缝加载配置文件,而不需要重启服务,以下程序摘录自代码中的完整示例代码,示例代码没有做什么异常处理,大家如果使用的话可以把它更加完善一下,http_client.c全文如下
  1. /**************************************************************
  2. *     Copyright (C) 2014-2014 All rights reserved.
  3. *       @Version: 1.0
  4. *       @Created: 2015-4-12 08:38:58
  5. *        @Author: Muyun  Www.Mu-Yun.Com
  6. *   @Description: http客户端程序,用于向WEB服务器发起http请求,将返回
  7. *         结果写入文件
  8. *       @History:
  9. **************************************************************/

  10. #include   <stdio.h>
  11. #include   <stdlib.h>
  12. #include   <string.h>
  13. #include   <sys/socket.h>
  14. #include   <errno.h>
  15. #include   <unistd.h>
  16. #include   <netinet/in.h>
  17. #include   <limits.h>
  18. #include   <netdb.h>
  19. #include   <arpa/inet.h>
  20. #include   <ctype.h>
  21. #include   <sys/types.h>
  22. #include   <sys/stat.h>
  23. #include   <fcntl.h>

  24. FILE *gFile;

  25. /**
  26. * [url=home.php?mod=space&uid=190858]@brief[/url] http_string_strchr 搜索字符串右边起的第一个匹配字符
  27. *
  28. * @Param: s  原始字符串
  29. * @Param: x  待匹配的字符
  30. *
  31. * Returns: 索到即返回x对应的值,否则返回0
  32. */
  33. char* http_string_strchr(char* s, char x)
  34. {
  35.     int i = strlen(s);
  36.     if(!(*s))
  37.     {
  38.         return 0;
  39.     }
  40.     while(s[i-1])
  41.     {
  42.         if(strchr(s+(i-1), x))
  43.         {
  44.             return (s+(i-1));
  45.         }
  46.         else
  47.         {
  48.             i--;
  49.         }
  50.     }
  51.     return 0;
  52. }

  53. /**
  54. * @brief http_string_lower 字符串转换为全小写
  55. *
  56. * @Param: s  原始字符串
  57. */
  58. void   http_string_lower(char* s)
  59. {
  60.     char *p = s;

  61.     while(*p && *p!='\0' )
  62.     {
  63.         if(*p > 'A' && *p < 'Z')
  64.             *p = *p + 32;
  65.         p++;
  66.     }
  67. }

  68. /**
  69. * @brief http_gethost_info 字符串src中分析出网站地址和端口,并得到用户要下载的文件
  70. *
  71. * @Param: src  输入字符串
  72. * @Param: web  WEB地址
  73. * @Param: file  需要下载的文件
  74. * @Param: port  WEB端口号,默认为80
  75. */
  76. void http_gethost_info(char* src, char* web, char* file, int* port)
  77. {
  78.     char* pa;
  79.     char* pb;
  80.     memset(web, 0, sizeof(web));
  81.     memset(file, 0, sizeof(file));
  82.     *port = 0;
  83.     if(!(*src))
  84.     {
  85.         return;
  86.     }
  87.     pa = src;
  88.     if(!strncmp(pa, "http://", strlen("http://")))
  89.     {
  90.         pa = src+strlen("http://");
  91.     }
  92.     else if(!strncmp(pa, "https://", strlen( "https://")))
  93.     {
  94.         pa = src+strlen( "https://");
  95.     }
  96.     pb = strchr(pa, '/');
  97.     if(pb)
  98.     {
  99.         memcpy(web, pa, strlen(pa)-strlen(pb));
  100.         if(pb+1)
  101.         {
  102.             memcpy(file, pb+1, strlen(pb)-1);
  103.             file[strlen(pb)-1] = 0;
  104.         }
  105.     }
  106.     else
  107.     {
  108.         memcpy(web, pa, strlen(pa));
  109.     }
  110.     if(pb)
  111.     {
  112.         web[strlen(pa) - strlen(pb)] = 0;
  113.     }
  114.     else
  115.     {
  116.         web[strlen(pa)] = 0;
  117.     }
  118.     pa = strchr(web, ':');
  119.     if(pa)
  120.     {
  121.         *port = atoi(pa + 1);
  122.     }
  123.     else
  124.     {
  125.         *port = 80;
  126.     }
  127. }

  128. /**
  129. * @brief http_open_file
  130. *
  131. * @Param: file_path
  132. *
  133. * Returns:
  134. */
  135. FILE *http_open_file(char *file_path)
  136. {
  137.     gFile = fopen(file_path,"a+");
  138.     return gFile;
  139. }
  140. /**
  141. * @brief http_file_exsits 判断文件是否存在
  142. *
  143. * @Param: path 文件路径
  144. *
  145. * Returns: 存在返回true,不存在返回false
  146. */
  147. int http_file_exsits(const char *path)
  148. {
  149.     struct stat statbuf;
  150.     if(lstat(path, &statbuf) ==0)
  151.         return S_ISREG(statbuf.st_mode) != 0;//判断文件是否为常规文件
  152.     return 0;
  153. }
  154. /**
  155. * @brief http_socket_init 初始化套接字
  156. *
  157. * @Param: port
  158. * @Param: host_addr
  159. *
  160. * Returns: 返回套接字描述符
  161. */
  162. int http_socket_init(int port, char *host_addr)
  163. {
  164.     struct sockaddr_in   server_addr;
  165.     struct hostent   *host;
  166.     int sockfd;

  167.     if((host=gethostbyname(host_addr)) == NULL)/*取得主机IP地址*/
  168.     {
  169.         fprintf(stderr, "Gethostname   error,   %s\n ",   strerror(errno));
  170.         return -1;
  171.     }
  172.     /*   客户程序开始建立   sockfd描述符   */
  173.     if((sockfd=socket(AF_INET,SOCK_STREAM,0)) == -1)/*建立SOCKET连接*/
  174.     {
  175.         fprintf(stderr, "Socket   Error:%s\a\n ",strerror(errno));
  176.         return -1;
  177.     }

  178.     /*   客户程序填充服务端的资料   */
  179.     bzero(&server_addr,sizeof(server_addr));
  180.     server_addr.sin_family=AF_INET;
  181.     server_addr.sin_port=htons(port);
  182.     server_addr.sin_addr=*((struct in_addr*)host->h_addr);

  183.     /*   客户程序发起连接请求   */
  184.     if(connect(sockfd, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr)) == -1)/*连接网站*/
  185.     {
  186.         fprintf(stderr, "Connect   Error:%s\a\n ",strerror(errno));
  187.         return -1;
  188.     }
  189.     return sockfd;
  190. }
  191. /*********************************************************************
  192. *filename:   httpclient.c
  193. *purpose:   HTTP协议客户端程序,可以用来下载网页
  194. *********************************************************************/
  195. int   main(int   argc,   char   *argv[])
  196. {
  197.     int sockfd = 0;
  198.     char buffer[1024] = "";
  199.     int port = 0;
  200.     int nbytes = 0;
  201.     char host_file[1024] = "";
  202.     char host_addr[256] = "";
  203.     char request[1024] = "";
  204.     int send = 0;
  205.     int totalsend = 0;
  206.     int i = 0;
  207.     FILE *file_fd;
  208.     char *pt;
  209.     char psave[4096];
  210.     char *file_name;
  211.     size_t index = 0;

  212.     if(argc < 2)
  213.     {
  214.         fprintf(stderr, "Usage:%s   [web-address]   [file path]\n ",argv[0]);
  215.         exit(1);
  216.     }
  217.     printf( "parameter.1 is: %s\n ", argv[1]);

  218.     http_gethost_info(argv[1], host_addr, host_file, &port);/*分析网址、端口、文件名等*/
  219.     printf( "webhost:%s\n ", host_addr);
  220.     printf( "hostfile:%s\n ", host_file);
  221.     printf( "port:%d\n\n ", port);

  222.     file_name = argv[2];
  223.     if(! file_name)
  224.         file_name = host_file;
  225.     sockfd = http_socket_init(port, host_addr);

  226.     sprintf(request,   "GET   /%s   HTTP/1.1\r\nAccept:   */*\r\nAccept-Language:   zh-cn\r\n"
  227.             "User-Agent:   Mozilla/4.0   (compatible;   MSIE   5.01;   Windows   NT   5.0)\r\n"
  228.             "Host:   %s:%d\r\nConnection:   Close\r\n\r\n ", host_file, host_addr, port);

  229.     printf( "%s\n", request);/*准备request,将要发送给主机*/

  230.     /*取得真实的文件名*/
  231.     if(*host_file)
  232.     {
  233.         pt = http_string_strchr(host_file, '/');
  234.     }
  235.     else
  236.     {
  237.         pt = 0;
  238.     }

  239.     /*发送http请求request*/
  240.     send = 0;
  241.     totalsend = 0;
  242.     nbytes=strlen(request);
  243.     while(totalsend < nbytes)
  244.     {
  245.         send = write(sockfd, request+totalsend, nbytes-totalsend);
  246.         if(send == -1)
  247.         {
  248.             printf( "send error!%s\n ", strerror(errno));
  249.             exit(0);
  250.         }
  251.         totalsend += send;
  252.         printf("%d bytes send OK!\n ", totalsend);
  253.     }
  254.     /*请求结束,等待响应*/

  255.     /*将结果写回到文件*/
  256.     if(http_file_exsits(file_name) )
  257.     {
  258.         remove(file_name);
  259.     }
  260.     file_fd = http_open_file(file_name);
  261.     if(file_fd == NULL)
  262.     {
  263.         perror("Open file error!\n");
  264.         return -1;
  265.     }

  266.     i=0;
  267.     /*连接成功了,接收http响应,每次处理4096个字节*/
  268.     memset(psave,0,4096);
  269.     while((nbytes=read(sockfd,buffer,1))==1)
  270.     {
  271.         if(i < 4)
  272.         {
  273.             /*这里处理http头部*/
  274.             if(buffer[0] == '\r' || buffer[0] == '\n')
  275.             {
  276.                 i++;
  277.             }
  278.             else
  279.             {
  280.                 i = 0;
  281.             }
  282.             printf( "%c", buffer[0]);/*把http头信息打印在屏幕上*/
  283.         }
  284.         else /*如果结尾部分不为\r\n\r\n则表示头接收完毕,下面是请求内容*/
  285.         {
  286.             psave[index++] = buffer[0];
  287.             if(index > 4096)
  288.             {
  289.                 fwrite(psave,4096,1,file_fd);
  290.                 fflush(file_fd);
  291.                 memset(psave,0,4096);
  292.                 index = 0;
  293.             }

  294.         }
  295.     }
  296.     /*将剩余的字符写入文件*/
  297.     if(index <= 4096)
  298.     {
  299.         fwrite(psave,index,1,file_fd);
  300.         fflush(file_fd);
  301.     }
  302.     close(sockfd);
  303.     fclose(file_fd);
  304.     return 0;
  305. }
复制代码

编译:gcc http_client.c -o http_client

运行:./http_client  http://192.168.1.1/sql.conf  

也可以这样运行./http_client  192.168.1.1/sql.conf   /tmp/sql.conf  后面的参数为指定文件存储位置。

这样就会把远程服务器上的文件下载过来了。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则 返回列表 发新帖

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