- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试恢复因互联网故障而失败的下载。我用来检查 curl 下载是否成功的函数是:
curl_multi_info_read
此函数在网络中断时首次调用时返回正确的错误代码 (CURLE_COULDNT_CONNECT
)。如果我尝试再次调用它,它会返回 NULL 指针,这意味着没有消息。实际上,我正在使用返回错误代码来检查是否存在互联网连接。这让我很困扰,因为如果没有互联网,它不会在第二次调用时返回任何错误代码。任何人都可以告诉我如何使用这个函数来检查返回代码,因为这个错误代码(CURLE_COULDNT_CONNECT
)对我来说非常重要检查互联网状态并相应地从它的地方恢复下载当我恢复连接时停止....
为了恢复下载我正在使用
curl_easy_setopt (curl, CURLOPT_RESUME_FROM, InternalOffset);
每次我失去互联网连接时,我都会调用此函数来设置选项,以便在互联网连接恢复时可以恢复下载 ...
备注Daniel Stenberg :
以下是有关平台和 libcurl 版本的一些详细信息:
评论:
是的。你的看法是对的。我从堆栈中删除了 easy handle,通过设置新选项 (curl_easy_setopt(curl, CURLOPT_RESUME_FROM, InternalOffset)
) 再次添加到 multi handle,最后我做了 multi perform。如果他们没有互联网连接,它会返回正确的错误。我的问题是:每次失去互联网连接时是否需要重复上述步骤才能获得正确的错误?如果我不执行这些步骤,curl_multi_info_read 函数将始终返回 NULL。
我的另一个观察结果是,当互联网连接恢复时,下载开始恢复。它从之前停止的地方开始下载。这让我感到惊讶。当 curl 恢复互联网时,是否在内部负责恢复下载。如果这是对的吗?我真的需要小心恢复下载或让 curl 处理正确吗?
最佳答案
您没有明确说明您使用的是多界面
还是简单界面
值得一提的是您正在使用什么平台以及什么libcurl
你正在使用等
以下是针对 libcurl/7.21.6
的最小 curl easy
和multi
测试。
网线拔了,http server 也关了之类的~好像还可以吧。
这些可能对你有帮助:
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, dl_lowspeed_bytes); //bytes/sec
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, dl_lowspeed_time); //seconds
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
注意:您必须非常努力地使 curl
在连接中断时倒下。这是设计使然,但让一些人感到意外。
我怀疑您是否愿意使用 CURLOPT_TIMEOUT
。这将使传输超时。如果您的下载量很大,那么它几乎肯定会花费比您准备等待的时间更长的时间来确定您的网络连接是否有问题 - 超时会受到影响。相比之下,CURLOPT_LOW_SPEED_TIME
超时可能永远不会被命中,即使在经过数小时的传输时间之后也是如此。
curltest_easy.c:
/*----------------------------------------------------
curltest_easy.c
WARNING: for test purposes only ~
*/
#include <stdio.h>
#include <unistd.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#include <sys/stat.h>
static int dl_progress(void *clientp,double dltotal,double dlnow,double ultotal,double ulnow)
{
if (dlnow && dltotal)
printf("dl:%3.0f%%\r",100*dlnow/dltotal); //shenzi prog-mon
fflush(stdout);
return 0;
}
static size_t dl_write(void *buffer, size_t size, size_t nmemb, void *stream)
{
return fwrite(buffer, size, nmemb, (FILE*)stream);
}
int do_dl(void)
{
CURL *curl;
FILE *fp;
CURLcode curl_retval;
long http_response;
double dl_size;
int retval=0;
long dl_lowspeed_bytes=1000; //1K
long dl_lowspeed_time=10; //sec
/*put something biG here, preferably on a server that you can switch off at will ;) */
char url[] = {"http://fc00.deviantart.net/fs26/f/2008/134/1/a/Dragon_VII_by_NegativeFeedback.swf"};
char filename[]={"blah.dl"};
struct stat st={0};
if (!stat(filename, &st));
printf("st.st_size:[%ld]\n", st.st_size);
if(!(fp=fopen(filename, "ab"))) /*append binary*/
return 1;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl)
{
//http://linux.die.net/man/3/curl_easy_setopt
curl_easy_setopt(curl, CURLOPT_URL, url);
/*callbacks*/
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, dl_write);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, dl_progress);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
/*curl will keep running -so you have the freedom to recover
from network disconnects etc in your own way without
distrubing the curl task in hand. ** this is by design :p ** */
//curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60);
//curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30);
/*set up min download speed threshold & time endured before aborting*/
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, dl_lowspeed_bytes); //bytes/sec
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, dl_lowspeed_time); //seconds while below low spped limit before aborting
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_RESUME_FROM,st.st_size);
/*uncomment this to get curl to tell you what its up to*/
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
if(CURLE_OK != (curl_retval=curl_easy_perform(curl)))
{
printf("curl_retval:[%d]\n", curl_retval);
switch(curl_retval)
{
//Transferred a partial file
case CURLE_WRITE_ERROR: //can be due to a dropped connection
break;
//all defined in curl/curl.h
default: //suggest quitting on unhandled error
retval=0;
};
curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dl_size);
printf("CURLINFO_CONTENT_LENGTH_DOWNLOAD:%f\n", dl_size);
curl_retval=curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response);
//see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
printf("CURLINFO_RESPONSE_CODE:%ld\n", http_response);
switch(http_response)
{
case 0: //eg connection down from kick-off ~suggest retrying till some max limit
break;
case 200: //yay we at least got to our url
break;
case 206:
case 416: //http://www.checkupdown.com/status/E416.html
printf("ouch! you might want to handle this & others\n");
default: //suggest quitting on an unhandled error
retval=0;
};
}
else
{
printf("our work here is done ;)\n");
retval=2;
}
if (fp)
fclose(fp);
if (curl)
curl_easy_cleanup(curl);
}
printf("retval [%d]\n", retval);
return retval;
}
int main(void)
{
while (!do_dl())
{
usleep(5000);
}
return 0;
}
/* notes ----
$sudo apt-get install libcurl4-gnutls-dev
$ curl-config --libs
-L/usr/lib/i386-linux-gnu -lcurl -Wl,-Bsymbolic-functions
#oook. lets do it:
$ gcc -o curltest_easy curltest_easy.c -L/usr/lib/i386-linux-gnu -lcurl -Wl,-Bsymbolic-functions
$ ./curltest
*/
curltest_multi.c:
/*----------------------------------------------------
curltest_mult1.c
WARNING: for test purposes only ~
*/
#include <stdio.h>
#include <unistd.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#include <sys/stat.h>
typedef struct S_dl_byte_data
{
double new_bytes_received; //from the latest request
double existing_filesize;
} dl_byte_data, *pdl_byte_data;
static int dl_progress(pdl_byte_data pdata,double dltotal,double dlnow,double ultotal,double ulnow)
{
/*dltotal := hacky way of getting the Content-Length ~ less hacky would be to first
do a HEAD request & then curl_easy_getinfo with CURLINFO_CONTENT_LENGTH_DOWNLOAD*/
if (dltotal && dlnow)
{
pdata->new_bytes_received=dlnow;
dltotal+=pdata->existing_filesize;
dlnow+=pdata->existing_filesize;
printf(" dl:%3.0f%% total:%.0f received:%.0f\r",100*dlnow/dltotal, dltotal, dlnow); //shenzi prog-mon
fflush(stdout);
}
return 0;
}
static size_t dl_write(void *buffer, size_t size, size_t nmemb, void *stream)
{
return fwrite(buffer, size, nmemb, (FILE*)stream);
}
////////////////////////
int do_dl(void)
{
CURLM *multi_handle;
CURL *curl;
FILE *fp;
CURLcode curl_retval;
int retval=0;
int handle_count=0;
double dl_bytes_remaining, dl_bytes_received;
dl_byte_data st_dldata={0};
char curl_error_buf[CURL_ERROR_SIZE]={"meh"};
long dl_lowspeed_bytes=1000, dl_lowspeed_time=10; /* 1KBs for 10 secs*/
/*put something biG here, preferably on a server that you can switch off at will ;) */
char url[] = {"http://fc00.deviantart.net/fs26/f/2008/134/1/a/Dragon_VII_by_NegativeFeedback.swf"};
char outfilename[]={"blah.swf"}, filename[]={"blah.dl"};
struct stat st={0};
if (!(fp=fopen(filename, "ab")) || -1==fstat(fileno(fp), &st)) //append binary
return -1;
if (curl_global_init(CURL_GLOBAL_DEFAULT))
return -2;
if (!(multi_handle = curl_multi_init()))
return -3;
if (!(curl = curl_easy_init()))
return -4;
st_dldata.new_bytes_received=st_dldata.existing_filesize=st.st_size;
//http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
curl_easy_setopt(curl, CURLOPT_URL, url);
/*callbacks*/
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, dl_write);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, dl_progress);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &st_dldata);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
/*curl will keep running -so you have the freedom to recover from network disconnects etc
in your own way without distrubing the curl task in hand. ** this is by design :p **
The follwoing sets up min download speed threshold & time endured before aborting*/
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, dl_lowspeed_bytes); //bytes/sec
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, dl_lowspeed_time); //seconds while below low spped limit before aborting
//alternatively these are available in libcurl 7.25
//curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE,1L);
//curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE,10);
//curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL,10);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
/*uncomment this to get curl to tell you what its up to*/
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_error_buf);
do
{
if (st_dldata.new_bytes_received) //set the new range for the partial transfer if we have previously received some bytes
{
printf("resuming d/l..\n");
fflush(fp);
//get the new filesize & sanity check for file; on error quit outer do-loop & return to main
if (-1==(retval=fstat(fileno(fp), &st)) || !(st_dldata.existing_filesize=st.st_size)) break;
//see also: CURLOPT_RANGE for passing a string with our own X-Y range
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, st.st_size);
st_dldata.new_bytes_received=0;
}
printf("\n\nbytes already received:[%.0f]\n", st_dldata.existing_filesize);
//re-use the curl handle again & again & again & again... lol
curl_multi_add_handle(multi_handle, curl);
do //curl_multi_perform event-loop
{
CURLMsg *pMsg;
int msgs_in_queue;
while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle, &handle_count));
//check for any mesages regardless of handle count
while(pMsg=curl_multi_info_read(multi_handle, &msgs_in_queue))
{
long http_response;
printf("\nmsgs_in_queue:[%d]\n",msgs_in_queue);
if (CURLMSG_DONE != pMsg->msg)
{
fprintf(stderr,"CURLMSG_DONE != pMsg->msg:[%d]\n", pMsg->msg);
}
else
{
printf("pMsg->data.result:[%d] meaning:[%s]\n",pMsg->data.result,curl_easy_strerror(pMsg->data.result));
if (CURLE_OK != pMsg->data.result) printf("curl_error_buf:[%s]\n", curl_error_buf);
switch(pMsg->data.result)
{
case CURLE_OK: ///////////////////////////////////////////////////////////////////////////////////////
printf("CURLE_OK: ");
curl_easy_getinfo(pMsg->easy_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dl_bytes_remaining);
curl_easy_getinfo(pMsg->easy_handle, CURLINFO_SIZE_DOWNLOAD, &dl_bytes_received);
if (dl_bytes_remaining == dl_bytes_received)
{
printf("our work here is done ;)\n");
rename(filename, outfilename);
retval=1;
}
else
{
printf("ouch! st_dldata.new_bytes_received[%f]\n",st_dldata.new_bytes_received);
printf("ouch! dl_bytes_received[%f] dl_bytes_remaining[%f]\n",dl_bytes_received,dl_bytes_remaining);
retval=dl_bytes_received < dl_bytes_remaining ? 0 : -5;
}
break; /////////////////////////////////////////////////////////////////////////////////////////////////
case CURLE_COULDNT_CONNECT: //no network connectivity ?
case CURLE_OPERATION_TIMEDOUT: //cos of CURLOPT_LOW_SPEED_TIME
case CURLE_COULDNT_RESOLVE_HOST: //host/DNS down ?
printf("CURMESSAGE switch handle_count:[%d]\n",handle_count);
break; //we'll keep trying
default://see: http://curl.haxx.se/libcurl/c/libcurl-errors.html
handle_count=0;
retval=-5;
};
//see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
curl_retval=curl_easy_getinfo(pMsg->easy_handle, CURLINFO_RESPONSE_CODE, &http_response);
printf("CURLINFO_RESPONSE_CODE HTTP:[%ld]\n", http_response);
switch(http_response)
{
case 0: //eg connection down from kick-off ~suggest retrying till some max limit
case 200: //yay we at least got to our url
case 206: //Partial Content
break;
case 416:
//cannot d/l range ~ either cos no server support
//or cos we're asking for an invalid range ~ie: we already d/ld the file
printf("HTTP416: either the d/l is already complete or the http server cannot d/l a range\n");
retval=2;
default: //suggest quitting on an unhandled error
handle_count=0;
retval=-6;
};
}
}
if (handle_count) //select on any active handles
{
fd_set fd_read={0}, fd_write={0}, fd_excep={0};
struct timeval timeout={5,0};
int select_retval;
int fd_max;
curl_multi_fdset(multi_handle, &fd_read, &fd_write, &fd_excep, &fd_max);
if (-1 == (select_retval=select(fd_max+1, &fd_read, &fd_write, &fd_excep, &timeout)))
{
//errno shall be set to indicate the error
fprintf(stderr, "yikes! select error :(\n");
handle_count=0;
retval=-7;
break;
}
else{/*check whatever*/}
}
} while (handle_count);
curl_multi_remove_handle(multi_handle,curl);
printf("continue from here?");
getchar();
}
while(retval==0);
curl_multi_cleanup(multi_handle);
curl_easy_cleanup(curl);
curl_global_cleanup();
if (fp) fclose(fp);
return retval;
}
////////////////////////
int main(void)
{
int retval;
printf("\n\ncurl_multi d/l test ~curl version:[%s]\n", curl_version());
while (1!=(retval=do_dl()))
{
printf("retval [%d] continue?\n\n", retval);
printf("continue?");
getchar();
}
printf("\nend of test!\n\n", retval);
return retval;
}
/* notes ----
$sudo apt-get install libcurl4-gnutls-dev
$curl-config --libs
-L/usr/lib/i386-linux-gnu -lcurl -Wl,-Bsymbolic-functions
#oook. lets do it:
$gcc -o curltest_multi curltest_multi.c -L/usr/lib/i386-linux-gnu -lcurl -Wl,-Bsymbolic-functions
$./curltest_multi
*/
在开始全新的测试之前,您可能需要记住删除 blah.dl
文件。该程序故意不这样做,因此您可以预先截断现有文件以进行测试;)
NB: 对于这样的事情,你也许应该*不只是依赖于 CURLE_COULDNT_CONNECT
~你的代码应该主要是错误处理(如果你的程序是严格用于个人的,可能更少使用)
我更新了 curtest_multi.c 以演示 easy_handle
重用。
并且请注意以下来自 the documentation 的引述:
When a single transfer is completed, the easy handle is still left added to the multi stack. You need to first remove the easy handle with curl_multi_remove_handle(3) and then close it with curl_easy_cleanup(3), or possibly set new options to it and add it again with curl_multi_add_handle(3) to start another transfer.
关于c - 下载未使用 Curl C API 恢复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10448874/
当我尝试通过我的 .exe 文件从 url 下载 .pdf 文件时出现以下错误。 The server committed a protocol violation. Section=Response
我是一家非营利组织的 G Suite 管理员,刚刚发现数据导出功能,这似乎是个人帐户的外卖。 导出文件已准备好,现在可以从 Google Cloud Platform Storage 中的存储桶下载。
导航 引言 总体思路 七牛云相关的配置文件 获取七牛云上传token 相关类定义 核心代码实现 获取七牛云图片下载链接 公开空
这不是后端编程问题。我只能修改标记或脚本(或文档本身)。我在这里问的原因是因为我对适当术语的所有搜索都不可避免地导致有关编程此功能的问题和解决方案。我不是试图通过编程来强制它;我必须找出此 PDF 行
您好,我已在 Google AdSense 中注册,我想使用适用于 iOS 的 SDK,但目前我找不到 SDK 下载链接。 我的申请已获批准。 任何人都知道如何下载这个sdk。 我使用这个链接来描述如
我需要为当前在 SourceForge 上的 github 项目提供二进制文件和文档。在那里,我可以为我需要的下载提供一个目录结构,因为我必须为大约 10 个不同的操作系统提供几个版本。 github
我从 Canvas 下载绘图时遇到问题。这是我的代码: function downloadCanvas(link, canvasId, filename) { link.href =
ASP.NET 项目 我将使用 Azure 进行存储。问题(要求): 在我的项目中,我让注册用户下载文件。但我不希望用户将此下载链接分享给未注册的人(例如:我给注册用户的下载链接只能在他们的计算机上下
我编写了一个servlet,用于检查http header ,但我不知道为什么当页面加载时,它会自动开始下载。 /* * To change this template, choose To
我正在尝试将下载添加到我的网络浏览器,但遇到的问题是获取您尝试下载的文件的名称。这是我的下载代码: engine.locationProperty().addListener(new ChangeLi
我正在尝试下载网站的 html: String encoding = "UTF-8"; HttpContext localContext = new BasicHttpContext();
我制作了一个带有“开始下载”按钮的框架,用于从网站下载 JAR。 问题是每当我点击开始下载按钮时,整个框架就会卡住,直到下载完成,然后就正常了。 我该如何解决这个问题? 这是单击按钮时执行的代码 p
我得到这段代码来实现一些东西,它可以帮助我从给定的 URL 下载文件。 -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSes
我正在尝试创建一个 Controller 来使用流方法下载和上传文件,在我的例子中,所有文件都作为 Blob 保存在数据库中。我阅读了 Jboss Netty 的文档,但我认为这不是我的最佳解决方案。
下载并保存文件 let destination: DownloadRequest.DownloadFileDestination = { _, _ in // var fileURL = sel
使用 htaccess 我基本上试图禁止访问该页面,即 http://example.com , 但它仍然允许人们下载文件,如果他们有直接链接即 http://example.com/hi.zip .
我正在寻求将脚本与我的控制面板集成,并且由于我是新手脚本编写者而遇到问题。我想做的是用 1 个脚本下载一个文件并解压它。 示例: wget http://example.com/example.tar
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
这个问题在这里已经有了答案: Top techniques to avoid 'data scraping' from a website database (14 个答案) 关闭 5 年前。 我有
这个问题在这里已经有了答案: Reading and parsing email from Gmail using C#, C++ or Python (6 个答案) 关闭 7 年前。 我只是想,是
我是一名优秀的程序员,十分优秀!