362 Stimmen

Wie macht man eine HTTP-Anfrage mit C++?

Gibt es eine Möglichkeit, mit C++ leicht einen HTTP-Request zu erstellen? Speziell möchte ich den Inhalt einer Seite (einer API) herunterladen und den Inhalt überprüfen, um zu sehen, ob er eine 1 oder eine 0 enthält. Ist es auch möglich, den Inhalt in einen String herunterzuladen?

2 Stimmen

Nein, derzeit gibt es keine integrierte Unterstützung entweder über die Sprache oder die Standardbibliothek für Netzwerke. Es gibt jedoch einen Networking TS N4370. Ich habe auch für diese Frage gestimmt, da sie Bibliotheksempfehlungen anzieht.

0 Stimmen

Wie wäre es mit BoostBeast?

3 Stimmen

@user3920237 Glücklicherweise denken die meisten Menschen nicht destruktiv, um die nützliche Frage zu VTC. Diese sind für den Gebrauch der Menschen gemacht, sei es Bibliothek.

331voto

neuro Punkte 14332

Ich hatte das gleiche Problem. libcurl ist wirklich umfassend. Es gibt einen C++-Wrapper curlpp, der für dich interessant sein könnte, da du nach einer C++-Bibliothek fragst. neon ist eine andere interessante C-Bibliothek, die auch WebDAV unterstützt.

curlpp scheint natürlich, wenn du C++ verwendest. Es gibt viele Beispiele in der Quellverteilung. Um den Inhalt einer URL abzurufen, kannst du etwas Ähnliches tun (extrahiert aus Beispielen):

// Edit: für cURLpp 0.7.3 umgeschrieben
// Hinweis: Namespace geändert, war in 0.7.2 cURLpp ...

#include 
#include 

// RAII-Cleanup

curlpp::Cleanup myCleanup;

// Anfrage senden und ein Ergebnis erhalten.
// Hier verwende ich eine Abkürzung, um es in einem String-Stream zu erhalten ...

std::ostringstream os;
os << curlpp::options::Url(std::string("http://example.com"));

string asAskedInQuestion = os.str();

Siehe das examples Verzeichnis in der curlpp-Quellverteilung, dort gibt es viele komplexere Fälle sowie ein einfaches vollständiges minimales Beispiel mit curlpp.

meine 2 Cent ...

2 Stimmen

Die neueste Version scheint unter Mac kaputt zu sein.. Etwas stimmt nicht mit der config.h, wenn sie als Bibliothek verknüpft ist.

0 Stimmen

Könnten Sie bitte ein Beispielprojekt bereitstellen? Ich habe Ihren gegebenen Code ausprobiert, aber ich kann ihn nicht ausführen.

0 Stimmen

@Zain: Schau dir die curlpp-Beispiele wie: curlpp.org/index.php/examples/47-example-00 an.

139voto

Software_Designer Punkte 8090

Windows Code:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#pragma comment(lib,"ws2_32.lib")

int main( void ){

WSADATA wsaData;
SOCKET Socket;
SOCKADDR_IN SockAddr;
int lineCount=0;
int rowCount=0;
struct hostent *host;
locale local;
char buffer[10000];
int i = 0 ;
int nDataLength;
string website_HTML;

// website url
string url = "www.google.com";

//HTTP GET
string get_http = "GET / HTTP/1.1\r\nHost: " + url + "\r\nConnection: close\r\n\r\n";

    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
        cout << "WSAStartup failed.\n";
        system("pause");
        //return 1;
    }

    Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    host = gethostbyname(url.c_str());

    SockAddr.sin_port=htons(80);
    SockAddr.sin_family=AF_INET;
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);

    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){
        cout << "Could not connect";
        system("pause");
        //return 1;
    }

    // send GET / HTTP
    send(Socket,get_http.c_str(), strlen(get_http.c_str()),0 );

    // recieve html
    while ((nDataLength = recv(Socket,buffer,10000,0)) > 0){        
        int i = 0;
        while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'){

            website_HTML+=buffer[i];
            i += 1;
        }               
    }

    closesocket(Socket);
    WSACleanup();

    // Display HTML source 
    cout<

`Hier ist eine viel bessere Implementierung:

#include 
#include 
#include 

using std::string;

#pragma comment(lib,"ws2_32.lib")

HINSTANCE hInst;
WSADATA wsaData;
void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename);
SOCKET connectToServer(char *szServerName, WORD portNum);
int getHeaderLength(char *content);
char *readUrl2(char *szUrl, long &bytesReturnedOut, char **headerOut);

int main()
{
    const int bufLen = 1024;
    char *szUrl = "http://stackoverflow.com";
    long fileSize;
    char *memBuffer, *headerBuffer;
    FILE *fp;

    memBuffer = headerBuffer = NULL;

    if ( WSAStartup(0x101, &wsaData) != 0)
        return -1;

    memBuffer = readUrl2(szUrl, fileSize, &headerBuffer);
    printf("returned from readUrl\n");
    printf("data returned:\n%s", memBuffer);
    if (fileSize != 0)
    {
        printf("Got some data\n");
        fp = fopen("downloaded.file", "wb");
        fwrite(memBuffer, 1, fileSize, fp);
        fclose(fp);
         delete(memBuffer);
        delete(headerBuffer);
    }

    WSACleanup();
    return 0;
}

void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename)
{
    string::size_type n;
    string url = mUrl;

    if (url.substr(0,7) == "http://")
        url.erase(0,7);

    if (url.substr(0,8) == "https://")
        url.erase(0,8);

    n = url.find('/');
    if (n != string::npos)
    {
        serverName = url.substr(0,n);
        filepath = url.substr(n);
        n = filepath.rfind('/');
        filename = filepath.substr(n+1);
    }

    else
    {
        serverName = url;
        filepath = "/";
        filename = "";
    }
}

SOCKET connectToServer(char *szServerName, WORD portNum)
{
    struct hostent *hp;
    unsigned int addr;
    struct sockaddr_in server;
    SOCKET conn;

    conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (conn == INVALID_SOCKET)
        return NULL;

    if(inet_addr(szServerName)==INADDR_NONE)
    {
        hp=gethostbyname(szServerName);
    }
    else
    {
        addr=inet_addr(szServerName);
        hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
    }

    if(hp==NULL)
    {
        closesocket(conn);
        return NULL;
    }

    server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
    server.sin_family=AF_INET;
    server.sin_port=htons(portNum);
    if(connect(conn,(struct sockaddr*)&server,sizeof(server)))
    {
        closesocket(conn);
        return NULL;
    }
    return conn;
}

int getHeaderLength(char *content)
{
    const char *srchStr1 = "\r\n\r\n", *srchStr2 = "\n\r\n\r";
    char *findPos;
    int ofset = -1;

    findPos = strstr(content, srchStr1);
    if (findPos != NULL)
    {
        ofset = findPos - content;
        ofset += strlen(srchStr1);
    }

    else
    {
        findPos = strstr(content, srchStr2);
        if (findPos != NULL)
        {
            ofset = findPos - content;
            ofset += strlen(srchStr2);
        }
    }
    return ofset;
}

char *readUrl2(char *szUrl, long &bytesReturnedOut, char **headerOut)
{
    const int bufSize = 512;
    char readBuffer[bufSize], sendBuffer[bufSize], tmpBuffer[bufSize];
    char *tmpResult=NULL, *result;
    SOCKET conn;
    string server, filepath, filename;
    long totalBytesRead, thisReadSize, headerLen;

    mParseUrl(szUrl, server, filepath, filename);

    ///////////// step 1, connect //////////////////////
    conn = connectToServer((char*)server.c_str(), 80);

    ///////////// step 2, send GET request /////////////
    sprintf(tmpBuffer, "GET %s HTTP/1.0", filepath.c_str());
    strcpy(sendBuffer, tmpBuffer);
    strcat(sendBuffer, "\r\n");
    sprintf(tmpBuffer, "Host: %s", server.c_str());
    strcat(sendBuffer, tmpBuffer);
    strcat(sendBuffer, "\r\n");
    strcat(sendBuffer, "\r\n");
    send(conn, sendBuffer, strlen(sendBuffer), 0);

//    SetWindowText(edit3Hwnd, sendBuffer);
    printf("Buffer being sent:\n%s", sendBuffer);

    ///////////// step 3 - get received bytes ////////////////
    // Receive until the peer closes the connection
    totalBytesRead = 0;
    while(1)
    {
        memset(readBuffer, 0, bufSize);
        thisReadSize = recv (conn, readBuffer, bufSize, 0);

        if ( thisReadSize <= 0 )
            break;

        tmpResult = (char*)realloc(tmpResult, thisReadSize+totalBytesRead);

        memcpy(tmpResult+totalBytesRead, readBuffer, thisReadSize);
        totalBytesRead += thisReadSize;
    }

    headerLen = getHeaderLength(tmpResult);
    long contenLen = totalBytesRead-headerLen;
    result = new char[contenLen+1];
    memcpy(result, tmpResult+headerLen, contenLen);
    result[contenLen] = 0x0;
    char *myTmp;

    myTmp = new char[headerLen+1];
    strncpy(myTmp, tmpResult, headerLen);
    myTmp[headerLen] = NULL;
    delete(tmpResult);
    *headerOut = myTmp;

    bytesReturnedOut = contenLen;
    closesocket(conn);
    return(result);
}`

20 Stimmen

Ich konnte curlpp nicht zum Laufen bringen, also habe ich deinen Code verwendet. Danke

1 Stimmen

Ich habe diesen Code auf einem Windows Vista mit Dev-C++ Version 4.9.9.2 getestet. Beim Verlinken erhielt ich eine Reihe von Fehlern: [Linker-Fehler] Undefinierter Verweis auf `WSAStartup@8'

9 Stimmen

@Expanding-Dev Nur MSVC (Visual Studio) versteht "pragma comment". Wenn Sie etwas anderes verwenden, müssen Sie "ws2_32.lib" manuell verknüpfen (wie jede andere Bibliothek).

65voto

Homer6 Punkte 14461

Aktualisierung 2020: Ich habe eine neue Antwort, die diese jetzt 8 Jahre alte, ersetzt: https://stackoverflow.com/a/61177330/278976

Unter Linux habe ich cpp-netlib, libcurl, curlpp, urdl, boost::asio ausprobiert und auch Qt in Betracht gezogen (aber aufgrund der Lizenz abgelehnt). Alle diese waren entweder unvollständig für diesen Zweck, hatten schlampige Schnittstellen, hatten schlechte Dokumentationen, waren ungewartet oder unterstützten kein https.

Dann folgte ich dem Vorschlag von https://stackoverflow.com/a/1012577/278976 und probierte POCO aus. Wow, ich wünschte, ich hätte das vor Jahren entdeckt. Hier ist ein Beispiel für das Senden eines HTTP GET Requests mit POCO:

https://stackoverflow.com/a/26026828/2817595

POCO ist kostenlos, Open Source (Boost-Lizenz). Nein, ich habe keine Verbindung mit dem Unternehmen; ich mag einfach ihre Schnittstellen wirklich gerne. Tolle Arbeit Jungs (und Mädels).

https://pocoproject.org/download.html

Hoffe, das hilft jemandem... ich habe drei Tage gebraucht, um all diese Bibliotheken auszuprobieren.

1 Stimmen

2 Stimmen

Ich habe gerade Poco aufgrund deiner Empfehlung heruntergeladen. Mir wäre lieber etwas Leichtes, das auf STL und Boost aufbaut, anstatt viel davon neu zu schreiben. Außerdem bin ich kein Fan von CppUnit und mag es insbesondere nicht, Tests mit dem Build laufen zu lassen, und erwarte nicht, ihre Bibliothek testen zu müssen, während ich sie aufbaue.

1 Stimmen

Es ist etwas groß. Sie können jedoch den Bau der Tests und Beispiele (oder gemeinsam genutzte Bibliotheken) mit configure deaktivieren (d. h. --no-tests oder --no-samples oder --no-sharedlibs). Siehe github.com/pocoproject/poco/blob/develop/configure

63voto

huu Punkte 6394

Es wird eine neuere, weniger ausgereifte Curl-Wrapper namens C++ Requests entwickelt. Hier ist eine einfache GET-Anfrage:

#include 
#include 

int main(int argc, char** argv) {
    auto response = cpr::Get(cpr::Url{"http://httpbin.org/get"});
    std::cout << response.text << std::endl;
}

Es unterstützt eine Vielzahl von HTTP-Verben und Curl-Optionen. Hier findest du weitere Anwendungs-Dokumentationen hier.

Haftungsausschluss: Ich bin der Betreuer dieser Bibliothek.

17 Stimmen

Ich war gestern bei Ihrem CppCon 2015 Lightning Talk. Gut gemacht - sowohl der Vortrag als auch die Bibliothek. Mir gefällt besonders die "Curl für Menschen" Designphilosophie.

1 Stimmen

Hallo, ich bin gerade auf diesen Beitrag hier gestoßen, auf der Suche nach einfacheren C++-HTTP-Anfragen als auf herkömmliche Weise. Allerdings habe ich nicht wirklich Erfahrung mit Bibliotheken und ich weiß nicht wirklich, wie ich das in mein Visual Studio C++-Projekt einbinden soll. Gibt es irgendwo eine Erklärung? Ich habe das Gefühl, dass es nicht spezifisch für die Bibliothek ist, sondern eher dass ich im Allgemeinen nicht wirklich weiß, was ich mit dem vorliegenden Material machen soll.

2 Stimmen

@Sossenbinder, wenn Sie sich mit CMake vertraut machen, können Sie mithilfe davon Visual Studio-Builddateien für dieses Projekt generieren. Die Appveyor-Konfigurationsdatei enthält ein grobes Beispiel dafür, wie dies zu bewerkstelligen ist.

26voto

Homer6 Punkte 14461

Aktualisierte Antwort für April 2020:

In letzter Zeit hatte ich viel Erfolg mit cpp-httplib (sowohl als Client als auch als Server). Es ist ausgereift und erreicht ungefähr 6.000 RPS im Single-Thread-Modus.

Im Bereich der neuesten Technologien gibt es ein vielversprechendes Framework, cpv-framework, das auf zwei Kernen etwa 180.000 RPS erreichen kann (und sich gut mit der Anzahl der Kerne skalieren lässt, da es auf dem seastar-Framework basiert, das die schnellsten DBs der Welt, scylladb, antreibt).

Allerdings ist cpv-framework noch relativ neu; daher empfehle ich für die meisten Anwendungen nach wie vor cpp-httplib.

Es gibt auch einige andere Bibliotheken, wie cpr, die hier aufgelistet sind: https://github.com/lefticus/cpp_weekly/issues/44#issuecomment-1231847130

Diese Empfehlung ersetzt meine vorherige Antwort (vor 8 Jahren).

2 Stimmen

Ich mag den 1-Datei (5K-Zeilen sind ok) Ansatz von cpp-httplib wirklich. Hast du eine Vorstellung von seiner Leistungsfähigkeit?

3 Stimmen

@Hack06 Der grobe Richtwert lag bei etwa 6000 Anfragen pro Sekunde (APS).

0 Stimmen

Diese Bibliothek (cpp-httplib) funktioniert nicht unter Windows 8 und darunter ... Die Fehlermeldungen sind auch nicht sehr hilfreich. Außerdem gefällt mir nicht die Idee, dass ich für eine SSL-Verbindung ein ca-bundle.crt benötige. Für die Client-Seite ist dies nicht notwendig.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X