2012-02-23 21 views
8

Estoy tratando de descargar un archivo usando FTP, y en el medio si la conexión termina, entonces debe continuar desde donde se detuvo. Mi problema es que al usar el siguiente fragmento de código puedo continuar la descarga si cierro la conexión y luego la vuelvo a conectar, pero si lo hago en el sitio del servidor, entonces no puedo reanudar la descarga y el programa entra en estado infinito.Cómo reanudar la descarga de archivos a través de FTP usando Curl en C?

#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; 
} 

¿Alguien me puede decir que cómo puedo reanudar la descarga si la conexión está cerrada por un sitio remoto? Cualquier ayuda se agradece

Gracias,

Yuvi

+0

¿Hay algo así como http 'AddRange' en ftp? –

+0

sí, está allí, pero mi problema es que no puedo detectar el error si la conexión está cerrada, para saber un poco más puedes consultarlo aquí http://curl.haxx.se/libcurl/c/ftpuploadresume.html – Yuvi

Respuesta

2

Añadir un varaible a la estructura ftpfile a la función de su escritura consciente de la necesidad de appeand y decirle libcurl para reanudar la descarga desde el final de la archivo de destino mediante el establecimiento de CURLOPT_RESUME_FROM al número de bytes ya se han descargado:

struct FtpFile 
{ 
    const char *pcInfFil; 
    FILE *pFd; 
    int iAppend; 
}; 

En principal, si desea reanudar:

curl_easy_setopt(curl, CURLOPT_RESUME_FROM , numberOfBytesToSkip); 

Si el archivo no existe, o no es una descarga reanudado, pero una nueva descarga, asegúrese de ajustar CURLOPT_RESUME_FROM de nuevo a 0.

En my_fwrite:

out->stream=fopen(out->filename, out->iAppend ? "ab":"wb"); 

PD si donde tiene que reanudar el archivo es más grande que un largo (2 GB), mira en CURLOPT_RESUME_FROM_LARGE y CURL_OFF_T_C()

En respuesta al comentario solicitando información adicional sobre cómo saber cuándo una transferencia fallida:

Después llamar rizo decisión fácil realizar:

CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); 

recuperar del contexto rizo:

CURLINFO_HEADER_SIZE 
CURLINFO_CONTENT_LENGTH_DOWNLOAD 

sumarlos y asegurarse de que ae qual

CURLINFO_SIZE_DOWNLOAD 

Si no intenta volver a interpretar el contexto.

Y asegúrese de usar la última versión de curl, debe transcurrir el tiempo después de 60 segundos de no escuchar desde el servidor FTP desde donde se está descargando.

+0

gracias como respuesta, pero ¿cómo puedo saber que la conexión está cerrada por un sitio remoto, que el programa de ejemplo no funciona si está en estado infinito ...? – Yuvi

0

Puede usar los parámetros CURLOPT_CONNECTTIMEOUT y CURLOPT_TIMEOUT para especificar un tiempo de espera de conexión y un tiempo máximo de ejecución por manejador.

La otra manera (que solo funciona si está utilizando la interfaz fácil, no la múltiple) es usar una devolución de llamada con opción de socket, que puede establecer utilizando CURLOPT_SOCKOPTFUNCTION. En él, debe llamar a setsockopt() para el parámetro SO_RCVTIMEO a la cantidad máxima de tiempo que una conexión puede estar inactiva antes de que se elimine. es decir, si no se han recibido bytes en los últimos 5 segundos, suelte la conexión.

Cuestiones relacionadas