我正在尝试使用C ++中的libcurl管理下载的进度。 我已经设法用curl_easy做了这个,但curl_easy的问题是它阻止程序直到请求完成。
我需要使用curl_mutli,因此http请求是异步的,但是当我尝试更改为curl_multi时,我的进度函数停止工作。
我有以下curl_easy请求代码:
int progressFunc(void* p, double TotalToDownload, double NowDownloaded, double TotalToUpload, double NowUploaded) {
std::cout << TotalToDownload << ", " << NowDownloaded << std::endl;
return 0;
}
FILE* file = std::fopen(filePath.c_str(), "wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progressFunc);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
CURLcode res = curl_easy_perform(curl);
完美无缺,并在控制台上打印下载进度。
但是,当尝试修改此代码以使用curl_multi时,文件无法正确下载(显示0字节),下载进度回调函数仅显示0, 0
。
FILE* file = std::fopen(filePath.c_str(), "wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progressFunc);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
curl_multi_add_handle(curlm, curl);
int runningHandles;
CURLMcode res = curl_multi_perform(curlm, &runningHandles);
答案 0 :(得分:2)
<强> TL; DR :你应该在循环中调用curl_multi_perform
。如果你不使用事件循环和民意调查/ epoll,你应该坚持在单独的线程中使用curl_easy
。
curl_multi API的重点并非阻塞:您可以使用epoll或类似方法监控curl的非阻塞套接字并调用{{1},而不是在单个调用中神奇地下载整个文件每次有些数据从网络到达时。当你使用它的多模式时,curl本身不启动任何内部线程并且不监视它的套接字 - 你应该自己做。这允许编写高性能的事件循环,在同一个线程中运行多个同时的卷曲传输。需要的人通常已经拥有必要的安全带,或者可以自己轻松编写。
第一次调用curl_multi_perform
时,它很可能会在DNS解析完成之前和/或远程端接受TCP连接之前返回。因此,在第一次调用中传输的有效负载数据量确实为0.根据服务器配置,第二次调用可能也不会传输任何有效负载。通过&#34;有效载荷&#34;我指的是实际的应用程序数据(与DNS请求,SSL协商,HTTP标头和HTTP2帧元数据相对)。
要实际完成传输,您必须重复调用epoll_wait,curl_multi_perform和其他函数的数量,直到完成为止。 Curl's corresponding example在完成一次传输后停止,但实际上创建一个永久运行的线程更有利于处理应用程序生命周期内的所有HTTP传输。