转载

libcurl中curl_easy_perform卡死问题

LibCurl使用阻塞的方式来进行http下载,curl_easy_perform执行后,程序会在这里阻塞等待下载结束(成功OR失败),此时若下载一段时间后出现网络异常,curl_easy_perform不会返回失败,整个线程阻塞卡死。

问题分析

复现:连接无线网络,然后执行curl_easy_perform下载,下载过程中,断开无线网络,curl_easy_perform卡死,阻塞整个线程。

原因:当断开无线网络时,使用命令行netstat ano | findstr ‘连接ip’, 可以发现LibCurl的http连接并没有断开(不知道是不是windows系统的bug),如果将CURLOPT_TIMEOUT设置为无限等待,curl_easy_perform便会一直阻塞住线程。

解决方案

1、如果我们不将CURLOPT_TIMEOUT设置为无限等待,是不会出现上面问题,curl_easy_perform会在执行一段时间(由CURLOPT_TIMEOUR设置),结束并返回失败,但是如果设置合适的CURLOPT_TIMEOUT是个问题。

curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0); // blocking forever, cannot find a suitable value

2、使用multi模式下载, 而不使用easy模式, 此方法的唯一好处就是multi并不会阻塞, 而是立即返回. 但是缺点是带来了问题, 其一就是需要自己去阻塞, 当我们需要返回时再返回, 其二还需要启动一个线程, 需要自己控制整个过程的节奏。

3、在下载中, 另起一个线程, 若发现下载状态卡死(可以通过定期检查文件大小来实现), 则从外部中断下载线程. 此方法需另起线程, 而且直接中断线程, 会给整个程序带来不稳定。

4、设置CURLOPT_TIMEOUT为30s,以30s为间隔断点续传。

5、使用CURLOPT_LOW_SPEED_LIMIT, CURLOPT_LOW_SPEED_TIME

res = curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1024L);
res = curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 30L);

6、使用CURLOPT_PROGRESSFUNCTION设置进度表回调函数,可以在该回调函数内部检测下载是否出错,如果出现就中断curl_easy_perform,返回下载错误。

#include <curl/curl.h>
int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROGRESSFUNCTION, progress_callback);
原文  http://JerkWisdom.github.io/developing/3rdparty/libcurl-curl_easy_perform-blocking-problem/
正文到此结束
Loading...