2010-08-26 7 views
1

J'ai des difficultés à démarrer avec libcurl. Le code ci-dessous ne semble pas récupérer la page entière de l'URL spécifiée. Où vais-je mal?Problème lors de l'utilisation de libcurl: il ne semble pas obtenir la page entière

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <curl/curl.h> 
#include <curl/types.h> 
#include <curl/easy.h> 

using namespace std; 

char buffer[1024]; 

size_t tobuffer(char *ptr, size_t size, size_t nmemb, void *stream) 
{ 
    strncpy(buffer,ptr,size*nmemb); 
    return size*nmemb; 
} 

int main() { 
    CURL *curl; 
    CURLcode res; 


    curl = curl_easy_init(); 
    if(curl) { 
     curl_easy_setopt(curl, CURLOPT_URL, "http://google.co.in"); 
     curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,1); 
     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &tobuffer); 

     res = curl_easy_perform(curl); 

     printf("%s",buffer); 

     curl_easy_cleanup(curl); 
    } 
    return 0; 
} 

Répondre

1
char buffer[1024]; 

Comment pourriez-vous obtenir la page web entière lorsque votre taille de la mémoire tampon est limitée à 1024?

0

Je ne connais pas la bibliothèque, mais il me semble que vous réutilisez le tampon ... si la page que vous téléchargez ne rentre pas, vous l'écrivez à plusieurs reprises, et ne voyez probablement que la dernier extrait. Par exemple, si l'on copie l'alphabet dans un tampon de 10 caractères, on obtient:

 
ABCDEFGHIJ - first copy stores this 
KLMNOPQRST - second copy stores this 
UVWXYZ  - third copy stores this 

Selon que la taille des données déclarées comprend un caractère de fin 0/NUL, le tampon peut être considérée comme UVWXYZ (qui printf (% s) interprétera comme "UVWXYZ"), ou comme "UVWXYZQRST" (printf (% s) continuerait à essayer d'imprimer après la fin du tampon jusqu'à ce qu'il arrive juste de trouver un 0/NUL). Res = curl_easy_perform (curl) suggère fortement qu'il vous donne un résultat/code d'erreur, avez-vous pris la peine de vérifier ce que la valeur est et ce que la documentation dit que cela signifie?

Vous devriez vraiment apprendre à diagnostiquer vous-même ce genre de choses ... vous auriez trouvé le problème suspecté si au lieu de copier dans le tampon, vous mettez une instruction std :: cout dans votre callback pour afficher les données et combien de fois ça s'appelle. Brisez les choses jusqu'à ce que vous trouviez le problème.

6

Comme vu at the libcurl documentation for curl_easy_setopt(), la fonction de rappel est appelée autant de fois que nécessaire pour fournir tous les octets de la page récupérée. Votre fonction écrase le même tampon à chaque appel, avec le résultat qu'après curl_easy_perform() a fini d'aller chercher le fichier, vous avez seulement quelque chose qui soit dans l'appel final à tobuffer() gauche.

En résumé, votre fonction tobuffer() doit faire autre chose que remplacer le même tampon à chaque appel.

mise à jour

Par exemple, vous pouvez faire quelque chose comme le code suivant complètement non testé:

struct buf { 
    char *buffer; 
    size_t bufferlen; 
    size_t writepos; 
} buffer = {0}; 

size_t tobuffer(char *ptr, size_t size, size_t nmemb, void *stream) 
{ 
    size_t nbytes = size*nmemb; 
    if (!buffer.buffer) { 
     buffer.buffer = malloc(1024); 
     buffer.bufferlen = 1024; 
     buffer.writepos = 0; 
    } 
    if (buffer.writepos + nbytes < buffer.bufferlen) { 
     buffer.bufferlen = 2 * buffer.bufferlen; 
     buffer.buffer = realloc(buffer, buffer.bufferlen); 
    } 
    assert(buffer.buffer != NULL); 
    memcpy(buffer.buffer+buffer.writepos,ptr,nbytes); 
    return nbytes; 
} 

À un certain moment plus tard dans votre programme, vous devrez libérer la mémoire allouée quelque chose comme ça :

void freebuffer(struct buf *b) { 
    free(b->buffer); 
    b->buffer = NULL; 
    b->bufferlen = 0; 
    b->writepos = 0; 
} 

, notez aussi que je l'ai utilisé memcpy() au lieu de strncpy() pour déplacer les données vers le tampon. Ceci est important car libcurl ne prétend pas que les données passées à la fonction de rappel sont en réalité une chaîne ASCII terminée par NUL. En particulier, si vous récupérez un fichier image .gif, il peut certainement contenir (et contiendra) zéro octet dans le fichier que vous souhaitez conserver dans votre tampon. strncpy() va arrêter la copie après la première NUL qu'il voit dans les données source.

Comme un exercice pour le lecteur, j'ai laissé toute la gestion des erreurs de ce code. Vous devez en mettre.En outre, j'ai également laissé dans une fuite de mémoire juteuse au hasard que l'appel à realloc() échoue.

Une autre amélioration consisterait à utiliser l'option permettant à la valeur du paramètre stream d'être rappelé par l'appelant libcurl. Cela pourrait être utilisé pour allouer gérer votre tampon sans utiliser de variables globales. Je recommande fortement de le faire aussi.

+0

pouvez-vous me dire alors comment puis-je faire pour stocker le contenu entier dans un tableau de caractères global – raj

+0

J'ai ajouté un exemple de code.Ce n'est pas testé.Mais il devrait être un point de départ. – RBerteig

1

Vous exécutez une opération d'obtention simple à l'aide de libcurl. Vous pouvez utiliser cet exemple de programme comme référence. Pourquoi ne pas imprimer le tampon dans le rappel ou écrire dans un fichier comme indiqué dans cet exemple?

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

#include <curl/curl.h> 
#include <curl/types.h> 
#include <curl/easy.h> 

static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) 
{ 
    int written = fwrite(ptr, size, nmemb, (FILE *)stream); 
    return written; 
} 

int main(int argc, char **argv) 
{ 
    CURL *curl_handle; 
    static const char *headerfilename = "head.out"; 
    FILE *headerfile; 
    static const char *bodyfilename = "body.out"; 
    FILE *bodyfile; 

    curl_global_init(CURL_GLOBAL_ALL); 

    /* init the curl session */ 
    curl_handle = curl_easy_init(); 

    /* set URL to get */ 
    curl_easy_setopt(curl_handle, CURLOPT_URL, "http://curl.haxx.se"); 

    /* no progress meter please */ 
    curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); 

    /* send all data to this function */ 
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); 

    /* open the files */ 
    headerfile = fopen(headerfilename,"w"); 
    if (headerfile == NULL) { 
    curl_easy_cleanup(curl_handle); 
    return -1; 
    } 
    bodyfile = fopen(bodyfilename,"w"); 
    if (bodyfile == NULL) { 
    curl_easy_cleanup(curl_handle); 
    return -1; 
    } 

    /* we want the headers to this file handle */ 
    curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, headerfile); 

    /* 
    * Notice here that if you want the actual data sent anywhere else but 
    * stdout, you should consider using the CURLOPT_WRITEDATA option. */ 

    /* get it! */ 
    curl_easy_perform(curl_handle); 

    /* close the header file */ 
    fclose(headerfile); 

    /* cleanup curl stuff */ 
    curl_easy_cleanup(curl_handle); 

    return 0; 
} 
+0

je dois traiter le contenu après l'avoir obtenu .... après l'avoir enregistré dans un fichier et l'avoir récupéré et le traitement est fastidieux processus – raj

+0

Eh bien, vous devrez enregistrer le contenu dans le bloc contiguos pour éviter l'écrasement. Pour cela, vous devrez maintenir, la valeur écrite des données et écrire le nouveau contenu à cet endroit. –

0

vous semblez manquer l'option CURLOPT_WRITEDATA. qui passe le premier argument de WRITEFUNCION to_buffer (char * ptr ...

curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); 
1

Astuce: Utilisez un stringstream Il suffit de remplacer votre tampon avec un stringstream et la sortie du contenu par: (string)<streamname>.str() Works pour moi!

+0

vous pourriez détailler plus la réponse. – ppaulojr