如何在C中使用Curl通过FTP恢复文件下载?
我正在尝试使用 FTP 下载文件,如果连接终止,那么它应该从停止的位置恢复。我的问题是,使用以下代码片段,如果我关闭连接然后再次连接它,我可以继续下载,但如果我在服务器站点这样做,那么我无法恢复下载,并且程序进入无限状态。
#include <stdio.h>
#include <curl/curl.h>
/*
* This is an example showing how to get a single file from an FTP server.
* It delays the actual destination file creation until the first write
* callback so that it won't create an empty file in case the remote file
* doesn't exist or something else fails.
*/
struct FtpFile {
const char *filename;
FILE *stream;
};
static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
{
struct FtpFile *out=(struct FtpFile *)stream;
if(out && !out->stream) {
/* open file for writing */
out->stream=fopen(out->filename, "wb");
if(!out->stream)
return -1; /* failure, can't open file to write */
}
return fwrite(buffer, size, nmemb, out->stream);
}
int main(void)
{
CURL *curl;
CURLcode res;
struct FtpFile ftpfile={
"dev.zip", /* name to store the file as if succesful */
NULL
};
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl) {
/*
* You better replace the URL with one that works!
*/
curl_easy_setopt(curl, CURLOPT_URL,
"ftp://root:[email protected]/dev.zip");
/* Define our callback to get called when there's data to be written */
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
/* Set a pointer to our struct to pass to the callback */
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
/* Switch on full protocol/debug output */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
if(CURLE_OK != res) {
/* we failed */
fprintf(stderr, "curl told us %d\n", res);
}
}
if(ftpfile.stream)
fclose(ftpfile.stream); /* close the local file */
curl_global_cleanup();
return 0;
}
谁能告诉我,如果远程站点关闭连接,我该如何恢复下载。 任何帮助将不胜感激
,谢谢,
尤维
I am trying to download file using FTP, and in between if connection terminates then it should resume from where it was stop. My problem is that using following code snippet I able to continue download if I close connection and then again connect it, but if I am do so at server site then I am not able to resume download, and program goes into infinites state.
#include <stdio.h>
#include <curl/curl.h>
/*
* This is an example showing how to get a single file from an FTP server.
* It delays the actual destination file creation until the first write
* callback so that it won't create an empty file in case the remote file
* doesn't exist or something else fails.
*/
struct FtpFile {
const char *filename;
FILE *stream;
};
static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
{
struct FtpFile *out=(struct FtpFile *)stream;
if(out && !out->stream) {
/* open file for writing */
out->stream=fopen(out->filename, "wb");
if(!out->stream)
return -1; /* failure, can't open file to write */
}
return fwrite(buffer, size, nmemb, out->stream);
}
int main(void)
{
CURL *curl;
CURLcode res;
struct FtpFile ftpfile={
"dev.zip", /* name to store the file as if succesful */
NULL
};
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl) {
/*
* You better replace the URL with one that works!
*/
curl_easy_setopt(curl, CURLOPT_URL,
"ftp://root:[email protected]/dev.zip");
/* Define our callback to get called when there's data to be written */
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
/* Set a pointer to our struct to pass to the callback */
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
/* Switch on full protocol/debug output */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
if(CURLE_OK != res) {
/* we failed */
fprintf(stderr, "curl told us %d\n", res);
}
}
if(ftpfile.stream)
fclose(ftpfile.stream); /* close the local file */
curl_global_cleanup();
return 0;
}
Could any one tell me that how can I resume download if connection is closed by remote site.
Any help would be appreciated
Thanks,
Yuvi
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在 ftpfile 结构中添加一个变量,以了解您的写入函数是否需要追加,并通过将 CURLOPT_RESUME_FROM 设置为已下载的字节数来告诉 libcurl 从目标文件末尾恢复下载:
在 main 中,如果您想恢复:
如果文件尚不存在,或者不是恢复下载而是新下载,请务必将 CURLOPT_RESUME_FROM 设置回 0
。 my_fwrite:
PS 如果您需要恢复文件的位置大于长文件(2GB),请查看 CURLOPT_RESUME_FROM_LARGE 和 CURL_OFF_T_C() 响应
请求有关如何知道传输何时失败的其他信息的评论:
在调用curl easy Perform call之后:
从curl上下文中检索:
将它们添加在一起并确保它们相等,
如果不相等,请尝试重新执行上下文。
并且一定要使用最新版本的curl,如果 60 秒没有收到来自 FTP 服务器的下载信息,它应该会超时。
Add a varaible to the ftpfile struct to aware your write function of the need to appeand and tell libcurl to resume the download from the end of the destination file by setting CURLOPT_RESUME_FROM to the number of bytes downloaded already:
In main, if you want to resume:
If you the file doesn't already exist, or it is not a resumed download but a new download, be sure to set CURLOPT_RESUME_FROM back to 0.
In my_fwrite:
P.S. if where you need to resume the file is larger than a long (2GB), look into CURLOPT_RESUME_FROM_LARGE and CURL_OFF_T_C()
In response to comment requesting additional information on how to know when a transfer failed:
After you call curl easy perform call:
Retrieve from the curl context:
Add them together and make sure they equal
If not try to reperform the context.
And be sure to use the latest version of curl, it should timeout after 60 seconds of not hearing from the FTP server it is downloading from.
您可以使用 CURLOPT_CONNECTTIMEOUT 和 CURLOPT_TIMEOUT 参数来指定每个句柄的连接超时和最大执行时间。
另一种方法(仅在您使用简单接口而不是多重接口时才有效)是使用套接字选项回调,您可以使用 CURLOPT_SOCKOPTFUNCTION 进行设置。其中,您必须为 SO_RCVTIMEO 参数调用setsockopt(),以设置连接在被删除之前可以空闲的最长时间。即,如果在过去 5 秒内没有收到任何字节,则断开连接。
You may use the CURLOPT_CONNECTTIMEOUT and CURLOPT_TIMEOUT parameters to specify a connect timeout and maximum execution time on a per-handle basis.
The other way (that only works if you're using the easy interface, not the multi one) is to use a socket option callback, that you can set using CURLOPT_SOCKOPTFUNCTION. In it, you must call setsockopt() for the SO_RCVTIMEO parameter to the maximum amount of time a connection can be idle before it should be dropped. i.e. if no bytes have been received in the last 5 seconds, then drop the connection.