ft4314094 发表于 2015-4-12 21:04:38

C语言写的http下载工具 源代码

C语言写的http下载工具 源代码

今天在处理下载文件时,发现在两台服务器做双机环境下,备机需要同步主机配置文件,而这些配置文件存放在WEB目录中的某些目录,相对路径已知,发现用系统自带的wget工具下载配置文件时,必须要把文件完整下载过来后再去读配置文件,这样感觉有点不灵活,于是自己写了一个HTTP下载工具,这样在获取配置文件内容时比较灵活,可以无缝加载配置文件,而不需要重启服务,以下程序摘录自代码中的完整示例代码,示例代码没有做什么异常处理,大家如果使用的话可以把它更加完善一下,http_client.c全文如下:

/**************************************************************
*   Copyright (C) 2014-2014 All rights reserved.
*       @Version: 1.0
*       @Created: 2015-4-12 08:38:58
*      @Author: MuyunWww.Mu-Yun.Com
*   @Description: http客户端程序,用于向WEB服务器发起http请求,将返回
*         结果写入文件
*       @History:
**************************************************************/

#include   <stdio.h>
#include   <stdlib.h>
#include   <string.h>
#include   <sys/socket.h>
#include   <errno.h>
#include   <unistd.h>
#include   <netinet/in.h>
#include   <limits.h>
#include   <netdb.h>
#include   <arpa/inet.h>
#include   <ctype.h>
#include   <sys/types.h>
#include   <sys/stat.h>
#include   <fcntl.h>

FILE *gFile;

/**
* @brief http_string_strchr 搜索字符串右边起的第一个匹配字符
*
* @Param: s原始字符串
* @Param: x待匹配的字符
*
* Returns: 索到即返回x对应的值,否则返回0
*/
char* http_string_strchr(char* s, char x)
{
    int i = strlen(s);
    if(!(*s))
    {
      return 0;
    }
    while(s)
    {
      if(strchr(s+(i-1), x))
      {
            return (s+(i-1));
      }
      else
      {
            i--;
      }
    }
    return 0;
}

/**
* @brief http_string_lower 字符串转换为全小写
*
* @Param: s原始字符串
*/
void   http_string_lower(char* s)
{
    char *p = s;

    while(*p && *p!='\0' )
    {
      if(*p > 'A' && *p < 'Z')
            *p = *p + 32;
      p++;
    }
}

/**
* @brief http_gethost_info 字符串src中分析出网站地址和端口,并得到用户要下载的文件
*
* @Param: src输入字符串
* @Param: webWEB地址
* @Param: file需要下载的文件
* @Param: portWEB端口号,默认为80
*/
void http_gethost_info(char* src, char* web, char* file, int* port)
{
    char* pa;
    char* pb;
    memset(web, 0, sizeof(web));
    memset(file, 0, sizeof(file));
    *port = 0;
    if(!(*src))
    {
      return;
    }
    pa = src;
    if(!strncmp(pa, "http://", strlen("http://")))
    {
      pa = src+strlen("http://");
    }
    else if(!strncmp(pa, "https://", strlen( "https://")))
    {
      pa = src+strlen( "https://");
    }
    pb = strchr(pa, '/');
    if(pb)
    {
      memcpy(web, pa, strlen(pa)-strlen(pb));
      if(pb+1)
      {
            memcpy(file, pb+1, strlen(pb)-1);
            file = 0;
      }
    }
    else
    {
      memcpy(web, pa, strlen(pa));
    }
    if(pb)
    {
      web = 0;
    }
    else
    {
      web = 0;
    }
    pa = strchr(web, ':');
    if(pa)
    {
      *port = atoi(pa + 1);
    }
    else
    {
      *port = 80;
    }
}

/**
* @brief http_open_file
*
* @Param: file_path
*
* Returns:
*/
FILE *http_open_file(char *file_path)
{
    gFile = fopen(file_path,"a+");
    return gFile;
}
/**
* @brief http_file_exsits 判断文件是否存在
*
* @Param: path 文件路径
*
* Returns: 存在返回true,不存在返回false
*/
int http_file_exsits(const char *path)
{
    struct stat statbuf;
    if(lstat(path, &statbuf) ==0)
      return S_ISREG(statbuf.st_mode) != 0;//判断文件是否为常规文件
    return 0;
}
/**
* @brief http_socket_init 初始化套接字
*
* @Param: port
* @Param: host_addr
*
* Returns: 返回套接字描述符
*/
int http_socket_init(int port, char *host_addr)
{
    struct sockaddr_in   server_addr;
    struct hostent   *host;
    int sockfd;

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

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

    /*   客户程序发起连接请求   */
    if(connect(sockfd, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr)) == -1)/*连接网站*/
    {
      fprintf(stderr, "Connect   Error:%s\a\n ",strerror(errno));
      return -1;
    }
    return sockfd;
}
/*********************************************************************
*filename:   httpclient.c
*purpose:   HTTP协议客户端程序,可以用来下载网页
*********************************************************************/
int   main(int   argc,   char   *argv[])
{
    int sockfd = 0;
    char buffer = "";
    int port = 0;
    int nbytes = 0;
    char host_file = "";
    char host_addr = "";
    char request = "";
    int send = 0;
    int totalsend = 0;
    int i = 0;
    FILE *file_fd;
    char *pt;
    char psave;
    char *file_name;
    size_t index = 0;

    if(argc < 2)
    {
      fprintf(stderr, "Usage:%s      \n ",argv);
      exit(1);
    }
    printf( "parameter.1 is: %s\n ", argv);

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

    file_name = argv;
    if(! file_name)
      file_name = host_file;
    sockfd = http_socket_init(port, host_addr);

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

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

    /*取得真实的文件名*/
    if(*host_file)
    {
      pt = http_string_strchr(host_file, '/');
    }
    else
    {
      pt = 0;
    }

    /*发送http请求request*/
    send = 0;
    totalsend = 0;
    nbytes=strlen(request);
    while(totalsend < nbytes)
    {
      send = write(sockfd, request+totalsend, nbytes-totalsend);
      if(send == -1)
      {
            printf( "send error!%s\n ", strerror(errno));
            exit(0);
      }
      totalsend += send;
      printf("%d bytes send OK!\n ", totalsend);
    }
    /*请求结束,等待响应*/

    /*将结果写回到文件*/
    if(http_file_exsits(file_name) )
    {
      remove(file_name);
    }
    file_fd = http_open_file(file_name);
    if(file_fd == NULL)
    {
      perror("Open file error!\n");
      return -1;
    }

    i=0;
    /*连接成功了,接收http响应,每次处理4096个字节*/
    memset(psave,0,4096);
    while((nbytes=read(sockfd,buffer,1))==1)
    {
      if(i < 4)
      {
            /*这里处理http头部*/
            if(buffer == '\r' || buffer == '\n')
            {
                i++;
            }
            else
            {
                i = 0;
            }
            printf( "%c", buffer);/*把http头信息打印在屏幕上*/
      }
      else /*如果结尾部分不为\r\n\r\n则表示头接收完毕,下面是请求内容*/
      {
            psave = buffer;
            if(index > 4096)
            {
                fwrite(psave,4096,1,file_fd);
                fflush(file_fd);
                memset(psave,0,4096);
                index = 0;
            }

      }
    }
    /*将剩余的字符写入文件*/
    if(index <= 4096)
    {
      fwrite(psave,index,1,file_fd);
      fflush(file_fd);
    }
    close(sockfd);
    fclose(file_fd);
    return 0;
}


编译:gcc http_client.c -o http_client

运行:./http_clienthttp://192.168.1.1/sql.conf

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

这样就会把远程服务器上的文件下载过来了。

Beatix 发表于 2015-4-26 03:10:46

只有对楼主表示感谢,才能表达我现在的心情!

diddom 发表于 2015-7-7 13:10:24

顶......叹为观止.....
页: [1]
查看完整版本: C语言写的http下载工具 源代码