使用Curl进行http请求及下载器设计


    Curl是一个跨平台的网络协议库。本文记录一些常见的请求http用法。

一、基本介绍

    curl_easy_setopt选项

1. CURLOPT_URL 访问的url

2. CURLOPT_WRITEFUNCTION 有数据来时,默认执行的function

    CURLOPT_WRITEDATA 可以设置一个文件流sink,有数据来时,默认写到这个sink里边;

3. CURLOPT_HEADERFUNCTION 与write同理,有header数据来时,默认执行的function

    CURLOPT_HEADERDATA header文件流sink

4. CURLOPT_TIMEOUT 传输timeout时间

    CURLOPT_CONNECTIONTIMEOUT 连接timeout时间

5. CURLOPT_FOLLOWLOCATION 允许重定向

    CURLOPT_FOLLOWLOCATION 允许重定向的次数

6. CURLOPT_RESUME_FROM 

    断点续传,传递一个long参数,指定开始传递的偏移量

二、基本的http GET/POST操作

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
#include <curl/curl.h>
//#include <curl/types.h>
#include <curl/easy.h>
 
FILE *fp;

size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
    printf("%s", ptr);
    int written = fwrite(ptr, size, nmemb, (FILE *)fp);
    return written;
}

size_t header_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
    printf("%s", ptr);
    int written = fwrite(ptr, size, nmemb, (FILE *)fp);
    return written;
}
 
int main(int argc, char *argv[])
{
    CURL *curl;
 
    curl_global_init(CURL_GLOBAL_ALL);
    curl=curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL,"http://www.baidu.com");
 
    if((fp=fopen("curltest.txt","w"))==NULL)
    {
        curl_easy_cleanup(curl);
        exit(1);
    }
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_data);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
    exit(0);
}

三、进度条显示下载文件的进度

CURLOPT_XFERINFOFUNCTION获取文件传输进度,其中CURLOPT_NOPROGRESS必须设置为false;

#include <stdio.h>
#include <curl/curl.h>
 
#define TIME_IN_US 1 /* microseconds */
#define TIMETYPE curl_off_t
#define TIMEOPT CURLINFO_TOTAL_TIME_T
#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL     3000000
#define STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES         6000
 
struct myprogress {
  TIMETYPE lastruntime; /* type depends on version, see above */
  CURL *curl;
};
 
/* this is how the CURLOPT_XFERINFOFUNCTION callback works */
static int xferinfo(void *p,
                    curl_off_t dltotal, curl_off_t dlnow,
                    curl_off_t ultotal, curl_off_t ulnow)
{
  struct myprogress *myp = (struct myprogress *)p;
  CURL *curl = myp->curl;
  TIMETYPE curtime = 0;
 
  curl_easy_getinfo(curl, TIMEOPT, &curtime);
 
  /* under certain circumstances it may be desirable for certain functionality
     to only run every N seconds, in order to do this the transaction time can
     be used */
  if((curtime - myp->lastruntime) >= MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL) {
    myp->lastruntime = curtime;
#ifdef TIME_IN_US
    fprintf(stderr, "TOTAL TIME: %" CURL_FORMAT_CURL_OFF_T ".%06ld\r\n",
            (curtime / 1000000), (long)(curtime % 1000000));
#else
    fprintf(stderr, "TOTAL TIME: %f \r\n", curtime);
#endif
  }
 
  fprintf(stderr, "UP: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T
          "  DOWN: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T
          "\r\n",
          ulnow, ultotal, dlnow, dltotal);
 
  if(dlnow > STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES)
    return 1;
  return 0;
}
 
int main(void)
{
  CURL *curl;
  CURLcode res = CURLE_OK;
  struct myprogress prog;
 
  curl = curl_easy_init();
  if(curl) {
    prog.lastruntime = 0;
    prog.curl = curl;
 
    curl_easy_setopt(curl, CURLOPT_URL, "https://www.baidu.com");
    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo);
    /* pass the struct pointer into the xferinfo function, note that this is
       an alias to CURLOPT_PROGRESSDATA */
    curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog);

 
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
    res = curl_easy_perform(curl);
 
    if(res != CURLE_OK)
      fprintf(stderr, "%s\n", curl_easy_strerror(res));
 
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  return (int)res;
}

四、断点续传

CURLOPT_RESUME_FROM_LARGE 实现断点续传

//采用CURLOPT_RESUME_FROM_LARGE 实现文件断点续传功能
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
 
#include <curl/curl.h>
//这个函数为CURLOPT_HEADERFUNCTION参数构造
/* 从http头部获取文件size*/
size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream) {
       int r;
       long len = 0;
 
       /* _snscanf() is Win32 specific */
       // r = _snscanf(ptr, size * nmemb, "Content-Length: %ld\n", &len);
 r = sscanf((const char*)ptr, "Content-Length: %ld\n", &len);
       if (r) /* Microsoft: we don't read the specs */
              *((long *) stream) = len;
 
       return size * nmemb;
}
 
/* 保存下载文件 */
size_t wirtefunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
        return fwrite(ptr, size, nmemb, (FILE*)stream);
}
 
/*读取上传文件 */
size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
       FILE *f = (FILE*)stream;
       size_t n;
 
       if (ferror(f))
              return CURL_READFUNC_ABORT;
 
       n = fread(ptr, size, nmemb, f) * size;
 
       return n;
}
 
// 下载 或者上传文件函数
int download(CURL *curlhandle, const char * remotepath, const char * localpath,
           long timeout, long tries)
{
    FILE *f;
    curl_off_t local_file_len = -1 ;
    long filesize =0 ;

    CURLcode r = CURLE_GOT_NOTHING;
    int c;
    struct stat file_info;
    int use_resume = 0;
    if(stat(localpath, &file_info) == 0)
    {
        local_file_len =  file_info.st_size;
        use_resume  = 1;
    }
    //采用追加方式打开文件,便于实现文件断点续传工作
    f = fopen(localpath, "ab+");
    if (f == NULL) {
          perror(NULL);
          return 0;
    }

    curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath);

    curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, timeout);  // 设置连接超时,单位秒
    //设置http 头部处理函数
    curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc);
    curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &filesize);
    // 设置文件续传的位置给libcurl
    curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM_LARGE, use_resume?local_file_len:0);

    curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, f);
    curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, wirtefunc);

    curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1L);
    curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);

    r = curl_easy_perform(curlhandle);
    fclose(f);
    if (r == CURLE_OK)
          return 1;
    else {
          fprintf(stderr, "%s\n", curl_easy_strerror(r));
          return 0;
    }
}
 
int main(int c, char **argv) {
       CURL *curlhandle = NULL;
 
       curl_global_init(CURL_GLOBAL_ALL);
       curlhandle = curl_easy_init();
 
       download(curlhandle , "http://www.baidu.com","curltest.txt",1,3);
       curl_easy_cleanup(curlhandle);
       curl_global_cleanup();
 
       return 0;
}

五、下载器设计

1. 封装curl;

2. 设计Source类,内部包含线程,负责读取数据到内部队列;

3. Source内部线程每读到128字节(实际可酌情增减)就组装成一个Block,push到本地Block队列中; 

4. Source包含Read接口,供外部读取数据;

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM