带有libcurl的下载功能,但它的工作不完整[关闭]

Posted

技术标签:

【中文标题】带有libcurl的下载功能,但它的工作不完整[关闭]【英文标题】:download function with libcurl, but it works incomplete [closed] 【发布时间】:2019-03-27 04:59:18 【问题描述】:

大家好,阅读这个话题,我的平台是win32。而且我在使用 libcurl 时遇到了问题。

我的目标是使用 libcurl 编写下载程序,其中包括请求下载文件的 url,将文件保存在本地(fwrite),在下载时显示进度条。

问题是它可以很好地下载非常小的文件,但是当请求像 30MB 这样的更大文件时,它在完成之前就停止了。

如何调试此程序以使其适用于任何大小的文件?

我不熟悉 libcurl,任何简单的细节都会有所帮助。我可以回答 curl_easy 系列如何调用多个回调函数、两个回调函数中的任何一个编码不正确或 libcurl 中缺少一些规则吗? 随便回答我什么。

我尝试过的事情:

1.我尝试过重新编译 libcurl 的版本。现在我使用的是使用“WITH_SSL=static”编译的 libcurl-7.64。

2.我尝试了很多网站,找到了线索:非常小(如80kb)文件的网站将完全下载进度条。但较大的文件(如 30Mb)将是不完整的。我的猜测之一是由于文件较大,它因某些传输问题而停止。

代码:

static FILE * fp;

static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)



    size_t nWrite = fwrite(ptr, size, nmemb, fp);

    return nWrite;



static int progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) 



    (void)ultotal;
    (void)ulnow;
    int totaldotz = 40;

    double fractiondownloaded = (double)dlnow / (double)dltotal;
    int dotz = (int)(fractiondownloaded * totaldotz);

    printf("%3.0f%% [", fractiondownloaded * 100);   //print the number percentage of the progress

    int i = 0;
    for (; i < dotz; i++)      //print "=" to show progress
        printf("=");
    

    for (; i < totaldotz; i++)       //print space to occupy the rest
        printf(" ");
    
    printf("]\r");
    fflush(stdout);

    return 0;


int download_function(CURL *curl,const char * url, const char * path)



    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
    fopen_s(&fp, path, "ab+");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3L);
    char * error = NULL;
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
    CURLcode retcCode = curl_easy_perform(curl);
    fclose(fp);
    const char* pError = curl_easy_strerror(retcCode);
    if (curl) 
        curl_easy_cleanup(curl);
    
    return 0;


【问题讨论】:

欢迎来到 SO。您的问题应提供minimal reproducible example。没有一个,它是不完整的,最终会被关闭。请edit你的问题来改进它 阅读How to debug small programs 并阅读更多关于HTTP 协议的信息。您可能希望使用调试选项重新编译 libcurl(例如使用 gcc -g 请打印pError看看是什么原因,是你设置的超时3s过期了吗? curl_easy_setopt(curl,CURLOPT_TIMEOUT,3L);取出后正常吗? 【参考方案1】:

@ccxxshow 似乎是对的。设置超时选项会给我 CURLE_OPERATION_TIMEDOUT 错误。

删除此行后,我可以成功下载大约 9MB 的 PDF 文件。

curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3L);

我的完整代码:

#include <curl/curl.h>

static FILE * fp;

static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)



    size_t nWrite = fwrite(ptr, size, nmemb, fp);

    return nWrite;



static int progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)



    (void)ultotal;
    (void)ulnow;
    int totaldotz = 40;

    double fractiondownloaded = (double)dlnow / (double)dltotal;
    int dotz = (int)(fractiondownloaded * totaldotz);

    printf("%3.0f%% [", fractiondownloaded * 100);   //print the number percentage of the progress

    int i = 0;
    for (; i < dotz; i++)      //print "=" to show progress
        printf("=");
    

    for (; i < totaldotz; i++)       //print space to occupy the rest
        printf(" ");
    
    printf("]\r");
    fflush(stdout);

    return 0;


int download_function(CURL *curl, const char * url, const char * path)


    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
    fopen_s(&fp, path, "ab+");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L);
    //curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3L);
    char * error = NULL;
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
    CURLcode retcCode = curl_easy_perform(curl);
    fclose(fp);
    const char* pError = curl_easy_strerror(retcCode);
    if (curl) 
        curl_easy_cleanup(curl);
    
    return 0;



int main()

    CURL *testCurl = NULL;
    const char *fileAddr = "https://gotocon.com/dl/goto-cph-2015/slides/AndersLybecker_and_SebastianBrandes_DevelopingIoTSolutionsWithWindows10AndAzure.pdf";
    download_function(testCurl, fileAddr, "my-9MB.pdf");

【讨论】:

感谢 Rita Han 和 @ccxxshowand 的回答,我也检测到超时“3s”设置得太快,无法下载正常的大尺寸文件。这是阻止程序正常运行的主要问题。 @S.Woung 如果答案可以帮助您解决问题,您可以accept it。它将帮助更多人搜索该主题。 当然。甜蜜的指南。

以上是关于带有libcurl的下载功能,但它的工作不完整[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

WinInet 在 Windows 7 中不工作 - Dev-C++

curl和curl-config中的libcurl不匹配。

Libcurl的初步实现tfp上传下载功能

Linux下使用libcurl实现FTP单个文件上传下载功能

libcurl传输错误,错误码180

Lambda nodejs - 不支持带有 libcurl 字节范围的 mediainfo