C libcurl wird in einen String ausgegeben


93

Ich möchte das Ergebnis dieser Curl-Funktion in einer Variablen speichern. Wie kann ich das tun?

#include <stdio.h>
#include <curl/curl.h>

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

  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
    res = curl_easy_perform(curl);

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  return 0;
}

danke, ich habe es so gelöst:

#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>

function_pt(void *ptr, size_t size, size_t nmemb, void *stream){
    printf("%d", atoi(ptr));
}

int main(void)
{
  CURL *curl;
  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, function_pt);
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
  system("pause");
  return 0;
}

1
Um in Ihrer Lösung in function_pt () darauf hinzuweisen, konvertieren Sie die Zeichenfolge in ptr in eine Ganzzahl, um sie in der Ausgabe wieder in eine Zeichenfolge zu konvertieren. Sie können den String direkt ausgeben (und die vollständige Antwort sehen).
zzz

2
Hier ist ein Link zum cURL-Beispiel curl.haxx.se/libcurl/c/getinmemory.html
lafferc

1
CURLcode res;wird nicht verwendet
fnc12

Dieselbe Frage, aber für C ++ anstelle von c gehen Sie hier: Speichern Sie das Ergebnis des cURL-Inhalts in einer Zeichenfolge in C ++
Trevor Boyd Smith

Antworten:


112

Sie können eine Rückruffunktion festlegen, um eingehende Datenblöcke mit zu empfangen curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, myfunc);

Der Rückruf akzeptiert ein benutzerdefiniertes Argument, das Sie mit festlegen können curl_easy_setopt(curl, CURLOPT_WRITEDATA, p)

Hier ist ein Codeausschnitt, der einen Puffer struct string {*ptr; len}an die Rückruffunktion übergibt und diesen Puffer bei jedem Aufruf mit realloc () vergrößert.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>

struct string {
  char *ptr;
  size_t len;
};

void init_string(struct string *s) {
  s->len = 0;
  s->ptr = malloc(s->len+1);
  if (s->ptr == NULL) {
    fprintf(stderr, "malloc() failed\n");
    exit(EXIT_FAILURE);
  }
  s->ptr[0] = '\0';
}

size_t writefunc(void *ptr, size_t size, size_t nmemb, struct string *s)
{
  size_t new_len = s->len + size*nmemb;
  s->ptr = realloc(s->ptr, new_len+1);
  if (s->ptr == NULL) {
    fprintf(stderr, "realloc() failed\n");
    exit(EXIT_FAILURE);
  }
  memcpy(s->ptr+s->len, ptr, size*nmemb);
  s->ptr[new_len] = '\0';
  s->len = new_len;

  return size*nmemb;
}

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

  curl = curl_easy_init();
  if(curl) {
    struct string s;
    init_string(&s);

    curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
    res = curl_easy_perform(curl);

    printf("%s\n", s.ptr);
    free(s.ptr);

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  return 0;
}

1
Nett. Noch schöner, wenn all diese size_t(außer sich lenselbst) deklariert würden const.
Alk

1
für C ++ hierstd::string gehen
Trevor Boyd Smith

33

Die folgende Antwort ist die C ++ - Methode, um dies std::stringanstelle einer nullterminierten Zeichenfolge zu tun . Es verwendet weiterhin eine Rückruffunktion (daran führt kein Weg vorbei), behandelt aber auch Zuordnungsfehler mit try / catch.

#include <iostream>
#include <string>
#include <curl/curl.h>

size_t CurlWrite_CallbackFunc_StdString(void *contents, size_t size, size_t nmemb, std::string *s)
{
    size_t newLength = size*nmemb;
    try
    {
        s->append((char*)contents, newLength);
    }
    catch(std::bad_alloc &e)
    {
        //handle memory problem
        return 0;
    }
    return newLength;
}
int main()
{
    CURL *curl;
    CURLcode res;

    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    std::string s;
    if(curl)
    {

        curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");

        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); //only for https
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); //only for https
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
        curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L); //remove this to disable verbose output


        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if(res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));
        }

        /* always cleanup */
        curl_easy_cleanup(curl);
    }

    std::cout<<s<<std::endl;

    std::cout<< "Program finished!" << std::endl;
}

Ich denke, std :: string :: append kann diese Rückruffunktion viel einfacher machen.
Rnickb

@rnickb Du hast recht; s->append((char*)contents. nmemb);arbeitet einwandfrei mit mir und ist prägnanter. Außerdem hat die offizielle Funktionssignatur für den Rückruf ein char*erstes Argument, sodass Sie dieses verwenden und das Casting weglassen können. Und schließlich wird s->resize()der neu zugewiesene Speicherplatz tatsächlich initialisiert. Da Sie es sowieso überschreiben werden, s->reserve()wäre es effizienter.
Jeinzi

Das hat mir sehr geholfen. Können Sie bitte auch ein Beispiel geben, wie es mit HTTP POST geht :-)
Lord Wolfenstein

9

Lesen Sie das Handbuch hier: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html Ich denke, Sie benötigen mehrere Aufrufe von CURL_SETOPT. Der erste ist die URL, die Sie verarbeiten möchten, der zweite ist wie folgt:

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, function_ptr);

Wobei function_ptr mit dieser Signatur übereinstimmt:

size_t function( void *ptr, size_t size, size_t nmemb, void *stream)

Was hier passiert, ist, dass Sie eine Rückruffunktion bezeichnen, die libcurl aufruft, wenn eine Ausgabe zum Schreiben von einer von Ihnen aufgerufenen Übertragung vorhanden ist. Sie können es automatisch in eine Datei schreiben lassen oder ihm einen Zeiger auf eine Funktion übergeben, die die Ausgabe selbst verarbeitet. Mit dieser Funktion sollten Sie in der Lage sein, die verschiedenen Ausgabezeichenfolgen zu einem Stück zusammenzusetzen und sie dann in Ihrem Programm zu verwenden.

Ich bin mir nicht sicher, welche anderen Optionen Sie möglicherweise festlegen müssen / was sich sonst noch auf das Verhalten Ihrer App auswirkt. Schauen Sie sich diese Seite also genau an.


0

Hier ist eine C ++ - Variante der akzeptierten Antwort von alex-jasmin

#include <iostream>
#include <string>
#include <curl/curl.h>

size_t writefunc(void *ptr, size_t size, size_t nmemb, std::string *s) 
{
  s->append(static_cast<char *>(ptr), size*nmemb);
  return size*nmemb;
}

int main(void)
{
  CURL *curl = curl_easy_init();
  if (curl)
  {
    std::string s;

    curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);

    CURLcode res = curl_easy_perform(curl);

    std::cout << s << std::endl;

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  return 0;
}

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.