【问题标题】:unfinished download with curl in C在 C 中使用 curl 未完成下载
【发布时间】:2017-11-25 08:05:09
【问题描述】:

我正在使用 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;
        }
    }
}

编辑--- 感谢 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;
    }
}

【问题讨论】:

    标签: c curl


    【解决方案1】:

    你可以设置一个超时选项

    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)
    

    另见the curl page

    循环示例

      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 库在连接不稳定的情况下会出现一些问题 - 现在可能会有更好的东西,请尝试最新的稳定版本。

    如果您在几天内没有得到更好的答案,请尝试添加 50 个代表的“赏金”以吸引更多关注。

    【讨论】:

    • 谢谢,但我不知道完成下载的确切时间,例如,如果用户以 10KB/s 的速度下载文件,则需要更长的时间。
    • 我试过你的代码,但未完成的文件仍然存在。
    • while( -- maxtries) 之前添加curl_easy_cleanup(curl) - 如果出现错误,您将在未清理前一个实例时再执行一次curl_easy_init()。不确定 curl 是如何编程的,但如果有一些静态数据与curl 相关联,则可能导致未定义的行为(并删除else 中的行为(失败...))。好的,权限被拒绝。我们走在正确的轨道上!尝试使用与程序运行时相同的用户手动删除该文件 - 如果您有权限问题,请使用 root 删除它(如果可以)并尝试重新运行程序。
    • 谢谢,我编辑了我的代码,但我仍在等待有人帮助创建简历功能。
    【解决方案2】:

    您正在寻找的是 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);
    }
    

    来源:https://curl.haxx.se/libcurl/c/CURLOPT_RESUME_FROM.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-03
      • 2018-04-03
      • 1970-01-01
      • 1970-01-01
      • 2010-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多