官方的例子:
https://curl.haxx.se/libcurl/c/example.html
事实上我们集成使用时希望
1.非阻塞,方便随时取消
2.看到进度
3.逐个下载
其他的暂时没啥叼用。
融合官网例子,自己做的测试代码如下,改改封装可用了:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#ifdef _WIN32
#define WAITMS(x) Sleep(x)
#else
/* Portable sleep for platforms other than Windows. */
#define WAITMS(x) \
struct timeval wait = { 0, (x) * 1000 }; \
(void)select(0, NULL, NULL, NULL, &wait);
#endif
#define HTTPURL "http://abc.efg.com/ddd.php"
struct MemoryStruct {
char *memory;
size_t size;
size_t length;
};
static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
printf("WriteMemoryCallback\n");
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
size_t totolsize = realsize + mem->size;
if (mem->length < totolsize) {
char *ptr = (char*)realloc(mem->memory, totolsize);
if (ptr == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->memory = ptr;
}
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size = totolsize;
//mem->memory[mem->size] = 0;
return realsize;
}
#define TIME_IN_US 1
#define TIMETYPE curl_off_t
#define TIMEOPT CURLINFO_TOTAL_TIME_T
#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL 3000000
#define STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES 600000000
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)
{
//printf("xferinfo\n");
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;
}
#define INIT_SIZE (1024*1024)
/*
* Simply download a HTTP file.
*/
int main(void)
{
CURL *http_handle;
CURLM *multi_handle;
int still_running = 0; /* keep number of running handles */
int repeats = 0;
struct MemoryStruct chunk;
chunk.memory = (char*)malloc(INIT_SIZE); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
chunk.length = INIT_SIZE;
curl_global_init(CURL_GLOBAL_DEFAULT);
http_handle = curl_easy_init();
/* set the options (I left out a few, you'll get the point anyway) */
curl_easy_setopt(http_handle, CURLOPT_URL, HTTPURL);
/* some servers don't like requests that are made without a user-agent
field, so we provide one */
curl_easy_setopt(http_handle, CURLOPT_USERAGENT, "live95xiu");
/* send all data to this function */
curl_easy_setopt(http_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(http_handle, CURLOPT_WRITEDATA, (void *)&chunk);
struct myprogress prog;
prog.lastruntime = 0;
prog.curl = http_handle;
curl_easy_setopt(http_handle, CURLOPT_XFERINFOFUNCTION, xferinfo);
/* pass the struct pointer into the xferinfo function, note that this is
an alias to CURLOPT_PROGRESSDATA */
curl_easy_setopt(http_handle, CURLOPT_XFERINFODATA, &prog);
curl_easy_setopt(http_handle, CURLOPT_NOPROGRESS, 0L);
/* init a multi stack */
multi_handle = curl_multi_init();
/* add the individual transfers */
curl_multi_add_handle(multi_handle, http_handle);
/* we start some action by calling perform right away */
curl_multi_perform(multi_handle, &still_running);
while (still_running) {
CURLMcode mc; /* curl_multi_wait() return code */
int numfds;
/* wait for activity, timeout or "nothing" */
mc = curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds);
if (mc != CURLM_OK) {
fprintf(stderr, "curl_multi_wait() failed, code %d.\n", mc);
break;
}
/* 'numfds' being zero means either a timeout or no file descriptors to
wait for. Try timeout on first occurrence, then assume no file
descriptors and no file descriptors to wait for means wait for 100
milliseconds. */
if (!numfds) {
repeats++; /* count number of repeated zero numfds */
if (repeats > 1) {
WAITMS(100); /* sleep 100 milliseconds */
}
}
else
repeats = 0;
curl_multi_perform(multi_handle, &still_running);
}
curl_multi_remove_handle(multi_handle, http_handle);
curl_easy_cleanup(http_handle);
curl_multi_cleanup(multi_handle);
curl_global_cleanup();
FILE *savefile;
/* open the file */
errno_t err = fopen_s(&savefile,"savefile", "wb");
size_t written = fwrite(chunk.memory, 1, chunk.size, (FILE *)savefile);
/* close the header file */
fclose(savefile);
free(chunk.memory);
return 0;
}