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接口,供外部读取数据;