我正在使用Curl库创建一个简单的C代码,使用MSVC从URL下载文件。 问题是如果在下载过程中连接断开,我的代码将冻结并且未完成的文件尚未从目录中删除。 我想要的是如果下载失败,程序必须重试连接或删除未完成的文件,然后再试一次。我更喜欢使用C库而不是C ++库。这是我正在使用的代码:
//lib for curl
#include <curl/curl.h>
#define CURL_STATICLIB
bool downloader3(string url, string file_path) {
CURL *curl;
FILE *fp;
CURLcode res;
curl = curl_easy_init();
if (curl) {
fp = fopen(file_path.c_str(), "wb");
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
//always cleanup
curl_easy_cleanup(curl);
fclose(fp);
double val;
res = curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD, &val);
if ((CURLE_OK == res) && (val>0))
printf("Average download speed: %0.3f kbyte/sec.\n", val / 1024);
if ((res == CURLE_OK)) {
printf("Download Successful!\r\n");
return true;
}
else {
printf("Downlaod Failed!\r\n");
remove(file_path.c_str()); //remove the temp file
return false;
}
}
}
EDIT --- 感谢RingØ回答。我修改了代码,但我正在寻找一个恢复功能,可以恢复不完整文件的下载。
bool downloader3(string url, string file_path) {
CURL *curl;
FILE *fp = NULL;
CURLcode res;
int status;
int maxtries = 3;
do {
printf("Doing try # %d\r\n", maxtries);
curl = curl_easy_init();
if (curl) {
fp = fopen(file_path.c_str(), "wb");
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); // 30 seconds
res = curl_easy_perform(curl);
//always cleanup
curl_easy_cleanup(curl);
fclose(fp);
if ((res == CURLE_OK)) {
printf("Download Successful!\r\n");
break;
//return true;
}
}
} while (--maxtries);
if (maxtries) { // was OK
//curl_easy_cleanup(curl); // clean curl / delete file?
//fclose(fp);
return true;
}
else {
printf("Download Failed!\r\n");
printf("file path is: %s", file_path.c_str());
Sleep(5000);
status = remove(file_path.c_str()); //remove the unfinished file
if (status == 0)
printf("%s file deleted successfully.\n", file_path);
else
{
printf("Unable to delete the file\n");
}
return false;
}
}
答案 0 :(得分:2)
您可以设置超时选项
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); // 30 seconds
如果操作未在30秒内完成,则触发超时。然后在while循环中检查结果值,例如
res = curl_easy_perform( ... );
if (res == CURLE_OK) {
break;
}
// delete file
// keep retrying (add a counter if necessary)
循环示例
int maxtries = 5;
do {
curl = curl_easy_init();
if (curl) {
...
res = curl_easy_perform( ... );
if (res == CURLE_OK) {
break;
}
// delete file, curl cleanup...
}
} while ( --maxtries );
if (maxtries) { // was OK
// clean curl / delete file?
}
这不是理想的解决方案,正如您所说,下载可能需要更多或更少的时间。如果超时足够大,这(应该)可以防止永无止境的程序。
已知Curl库在连接不稳定时会出现一些问题 - 现在可能会有更好的东西,请尝试最新的稳定构建。
如果您在几天内没有得到更好的答案,请尝试添加&#34; Bounty&#34; 50个代表以吸引更多关注。
答案 1 :(得分:0)
您正在寻找的是RESUME_FROM功能。要使用它,您必须知道要从哪个字节开始下载。在这个例子中,它是一个上传,但应该是相同的setopt技术。以下是curl网站的示例用法:
CURL *curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com");
/* resume upload at byte index 200 */
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, 200L);
/* ask for upload */
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* set total data amount to expect */
curl_easy_setopt(curl, CURLOPT_INFILESIZE, size_of_file);
/* Perform the request */
curl_easy_perform(curl);
}