Wie stellen Sie eine HTTP-Anfrage mit C ++?


258

Gibt es eine Möglichkeit, mit C ++ einfach eine HTTP-Anfrage zu stellen? Insbesondere möchte ich den Inhalt einer Seite (einer API) herunterladen und den Inhalt überprüfen, um festzustellen, ob er eine 1 oder eine 0 enthält. Ist es auch möglich, den Inhalt in eine Zeichenfolge herunterzuladen?


1
Nein, derzeit gibt es weder über die Sprache noch über die Standardbibliothek eine integrierte Unterstützung für das Netzwerk. Es gibt jedoch einen Networking TS N4370 . Ich habe diese Frage auch VTC gestellt, da sie Bibliotheksempfehlungen enthält.

Wie wäre es mit BoostBeast?
Twocrush

Antworten:


249

Ich hatte das gleiche Problem. libcurl ist wirklich vollständig. Es gibt einen C ++ - Wrapper- Curlpp , der Sie interessieren könnte, wenn Sie nach einer C ++ - Bibliothek fragen. neon ist eine weitere interessante C-Bibliothek, die auch WebDAV unterstützt .

curlpp scheint natürlich, wenn Sie C ++ verwenden. Die Quelldistribution enthält viele Beispiele. Um den Inhalt einer URL zu erhalten, gehen Sie wie folgt vor (aus Beispielen extrahiert):

// Edit : rewritten for cURLpp 0.7.3
// Note : namespace changed, was cURLpp in 0.7.2 ...

#include <curlpp/cURLpp.hpp>
#include <curlpp/Options.hpp>

// RAII cleanup

curlpp::Cleanup myCleanup;

// Send request and get a result.
// Here I use a shortcut to get it in a string stream ...

std::ostringstream os;
os << curlpp::options::Url(std::string("http://www.wikipedia.org"));

string asAskedInQuestion = os.str();

Sehen Sie sich das examplesVerzeichnis in der Curlpp-Quelldistribution an , es gibt viele komplexere Fälle sowie ein einfaches, vollständiges Minimal mit Curlpp.

meine 2 Cent ...


1
Die neueste Version scheint unter dem Mac kaputt zu sein. Bei der Verknüpfung als Bibliothek ist etwas mit config.h durcheinander.
Eugene

1
Nun, ich konnte das oben genannte nicht kompilieren. Das Ersetzen os << myRequest.perform();durch myRequest.setOpt( new curlpp::options::WriteStream( &os ) ); myRequest.perform();ergab jedoch Ergebnisse. Stellen Sie sicher, dass Sie diese Option nicht verwenden http://example.com. Dadurch wird eine leere Seite zurückgegeben. Besser zB verwenden http://www.wikipedia.org.
Zane

4
Wie baut man Curlpp in MSVS? Ich kann es nicht zum
Laufen

2
Ich bin mit der neuesten Bearbeitung von @ ryan-sam nicht einverstanden. Es war eindeutig die Absicht des Autors, "webdav" und nicht die Webentwicklung zu schreiben, da die angegebene Bibliothek explizit für "HTTP- und WebDAV-Operationen" erstellt wurde.
Bostrot

2
@ostrot: Ja das was ich meinte. Ich habe einen Link zurückgesetzt und hinzugefügt. Ich glaube, die Leute dachten, ich hätte webdev geschrieben. Wie schade :)
Neuro

115

Windows-Code:

#include <string.h>
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <vector>
#include <locale>
#include <sstream>
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<<website_HTML;

    // pause
    cout<<"\n\nPress ANY key to close.\n\n";
    cin.ignore(); cin.get(); 


 return 0;
}

Hier ist eine viel bessere Implementierung:

#include <windows.h>
#include <string>
#include <stdio.h>

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

Versuchte diesen Code unter Windows Vista, das mit Dev-C ++ Version 4.9.9.2 kompiliert wurde. Ich habe mir beim Verknüpfen eine Reihe von Fehlern gegeben: [Linker-Fehler] undefinierter Verweis auf `WSAStartup @ 8 '
Expanding-Dev

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

24
@ JuanLuisSoldi Ich denke, Sie müssen wirklich ein Windows-Entwickler sein, um die "Schönheit" dieses Codes zu schätzen ...
static_rtti

Was soll hier (mit recv) empfangen werden? Ich bekomme viel Kauderwelsch als Ausgabe. Warum haben Sie das, was Sie getan haben, in den Sendepuffer gestellt (z. B. GET / HTTP/1.1.1/... etc)? Wie finde ich heraus, wie ich das, was ich sende, formatiere?
LazerSharks

43

Update 2020: Ich habe eine neue Antwort, die diese jetzt 8-jährige ersetzt: https://stackoverflow.com/a/61177330/278976

Unter Linux habe ich cpp-netlib, libcurl, curlpp, urdl, boost :: asio ausprobiert und Qt in Betracht gezogen (aber basierend auf der Lizenz abgelehnt). Alle diese waren entweder für diese Verwendung unvollständig, hatten schlampige Schnittstellen, hatten eine schlechte Dokumentation, waren nicht gewartet oder unterstützten https nicht.

Dann habe ich auf Vorschlag von https://stackoverflow.com/a/1012577/278976 POCO ausprobiert. Wow, ich wünschte ich hätte das vor Jahren gesehen. Hier ist ein Beispiel für eine HTTP-GET-Anforderung mit POCO:

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

POCO ist kostenlos, Open Source (Boost-Lizenz). Und nein, ich bin dem Unternehmen nicht angeschlossen. Ich mag ihre Schnittstellen einfach sehr. Tolle Arbeit Jungs (und Mädels).

https://pocoproject.org/download.html

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



2
Ich habe gerade Poco auf Ihren Vorschlag heruntergeladen. Ich würde etwas Leichtes bevorzugen, das auf STL aufbaut und verstärkt, anstatt viel davon neu zu schreiben. Außerdem bin ich kein Fan von CppUnit und insbesondere von Hass-Tests, die mit dem Build ausgeführt werden, und erwarte nicht, dass ich ihre Bibliothek beim Erstellen testen muss.
CashCow

Es ist ein bisschen groß. Sie können jedoch das Erstellen der Tests und Beispiele (oder gemeinsam genutzten Bibliotheken) mit configure deaktivieren (z. B. --no-tests oder --no-samples oder --no-sharedlibs). Siehe github.com/pocoproject/poco/blob/develop/configure
Homer6

Danke für das. Ich möchte es trotzdem, da es mir wichtig ist, die Aufgaben zu erledigen, die ich erledigen muss. Und ich stelle fest, dass dort auch JSON-Parsing durchgeführt wird, was gut ist, da ich dies nach dem Senden der HTTP-Anfrage tun muss, für die ich die Bibliothek erhalten habe.
CashCow

Es ist eine Weile her, aber dies soll Sie nur wissen lassen, dass keiner Ihrer Links jetzt funktioniert, selbst das Github-Repo scheint entfernt zu sein ...
Hack06

33

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

#include <iostream>
#include <cpr.h>

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. Es gibt mehr Nutzungs Dokumentation hier .

Haftungsausschluss: Ich bin der Betreuer dieser Bibliothek .


10
Ich war gestern bei Ihrem CppCon 2015-Blitzgespräch. Gut gemacht - sowohl das Gespräch als auch die Bibliothek. Besonders gut gefällt mir die Designphilosophie "Curl for People".
U007D

Hallo, ich bin gerade auf diesen Beitrag hier gestoßen und habe nach einfacheren C ++ - HTTP-Anforderungen gesucht als auf einfache Weise. Ich bin jedoch nicht wirklich erfahren mit Bibliotheken und weiß nicht wirklich, wie ich dies in mein Visual Studio C ++ - Projekt aufnehmen soll. Gibt es irgendwo eine Erklärung? Ich habe das Gefühl, dass es nicht spezifisch für die Bibliothek ist, sondern dass ich nicht wirklich weiß, was ich mit dem anfangen soll, was ich jetzt im Allgemeinen vor mir habe.
Sossenbinder

2
@Sossenbinder, wenn Sie sich mit CMake vertraut machen können, können Sie damit Visual Studio-Builddateien für dieses Projekt generieren. Die Appveyor-Konfigurationsdatei enthält ein grobes Beispiel dafür.
Huu

2
Sieht gut aus, aber das Bauen ist die Hölle, also ist Ihre Bibliothek nutzlos. Ich kann mich nicht auf den Paketmanager verlassen (brauche eine zuverlässige Methode, um Deps extern hinzuzufügen) und brauche so schnell wie möglich eine funktionierende
Bibliothek

So macht man das. wenn Sie dies mit den 200 Zeilen der am zweithäufigsten bewerteten Antwort vergleichen .......
v.oddou

17

Hier ist mein minimaler Wrapper um cURL, um einfach eine Webseite als String abrufen zu können. Dies ist beispielsweise für Unit-Tests nützlich. Es ist im Grunde ein RAII-Wrapper um den C-Code.

Installieren Sie "libcurl" auf Ihrem Computer yum install libcurl libcurl-develoder einem gleichwertigen Computer .

Anwendungsbeispiel:

CURLplusplus client;
string x = client.Get("http://google.com");
string y = client.Get("http://yahoo.com");

Klassenimplementierung:

#include <curl/curl.h>


class CURLplusplus
{
private:
    CURL* curl;
    stringstream ss;
    long http_code;
public:
    CURLplusplus()
            : curl(curl_easy_init())
    , http_code(0)
    {

    }
    ~CURLplusplus()
    {
        if (curl) curl_easy_cleanup(curl);
    }
    std::string Get(const std::string& url)
    {
        CURLcode res;
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);

        ss.str("");
        http_code = 0;
        res = curl_easy_perform(curl);
        if (res != CURLE_OK)
        {
            throw std::runtime_error(curl_easy_strerror(res));
        }
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
        return ss.str();
    }
    long GetHttpCode()
    {
        return http_code;
    }
private:
    static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
    {
        return static_cast<CURLplusplus*>(userp)->Write(buffer,size,nmemb);
    }
    size_t Write(void *buffer, size_t size, size_t nmemb)
    {
        ss.write((const char*)buffer,size*nmemb);
        return size*nmemb;
    }
};

16

libCURL ist eine ziemlich gute Option für Sie. Je nachdem, was Sie tun müssen, sollte das Tutorial Ihnen sagen, was Sie wollen, speziell für die einfache Handhabung. Grundsätzlich können Sie dies jedoch tun, um die Quelle einer Seite anzuzeigen:

CURL* c;
c = curl_easy_init();
curl_easy_setopt( c, CURL_URL, "www.google.com" );
curl_easy_perform( c );
curl_easy_cleanup( c );

Ich glaube, dies wird dazu führen, dass das Ergebnis auf stdout gedruckt wird. Wenn Sie stattdessen damit umgehen möchten - was Sie vermutlich tun -, müssen Sie die CURL_WRITEFUNCTION festlegen. All dies wird in dem oben verlinkten Curl-Tutorial behandelt.


16

Wenn Sie eine C ++ - Lösung wünschen, können Sie Qt verwenden . Es hat eine QHttp-Klasse, die Sie verwenden können.

Sie können die Dokumente überprüfen :

http->setHost("qt.nokia.com");
http->get(QUrl::toPercentEncoding("/index.html"));

Qt bietet noch viel mehr, das Sie in einer gängigen C ++ - App verwenden können.


4
Ich denke, QHttp wurde in Qt 4.6 und späteren Versionen durch QNetworkAccessManager und verwandte Klassen ersetzt.
Juzzlin

3
QNetworkAccessManagerwurde seit Qt 4.4 dokumentiert; und in Qt 4.8 heißt es: QHttp - This class is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.Ich denke, es ist immer noch verfügbar, wenn Sie die veralteten Warnungen ignorieren.
Jesse Chisholm

13

Möglicherweise möchten Sie das C ++ REST SDK (Codename "Casablanca") überprüfen . http://msdn.microsoft.com/en-us/library/jj950081.aspx

Mit dem C ++ REST SDK können Sie von Ihrer C ++ - App aus einfacher eine Verbindung zu HTTP-Servern herstellen.

Anwendungsbeispiel:

#include <iostream>
#include <cpprest/http_client.h>

using namespace web::http;                  // Common HTTP functionality
using namespace web::http::client;          // HTTP client features

int main(int argc, char** argv) {
    http_client client("http://httpbin.org/");

    http_response response;
    // ordinary `get` request
    response = client.request(methods::GET, "/get").get();
    std::cout << response.extract_string().get() << "\n";

    // working with json
    response = client.request(methods::GET, "/get").get();
    std::cout << "url: " << response.extract_json().get()[U("url")] << "\n";
}

Das C ++ REST SDK ist ein Microsoft-Projekt für die Cloud-basierte Client-Server-Kommunikation in nativem Code unter Verwendung eines modernen asynchronen C ++ - API-Designs.


10

Mit dieser Antwort verweise ich auf die Antwort von Software_Developer . Beim Neuerstellen des Codes stellte ich fest, dass einige Teile veraltet sind ( gethostbyname()) oder keine Fehlerbehandlung (Erstellen von Sockets, Senden von etwas) für eine Operation bieten .

Der folgende Windows-Code wird mit Visual Studio 2013 und Windows 8.1 64-Bit sowie Windows 7 64-Bit getestet. Es zielt auf eine IPv4-TCP-Verbindung mit dem Webserver von www.google.com ab.

#include <winsock2.h>
#include <WS2tcpip.h>
#include <windows.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
    int main (){
    // Initialize Dependencies to the Windows Socket.
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
        cout << "WSAStartup failed.\n";
        system("pause");
        return -1;
    }

    // We first prepare some "hints" for the "getaddrinfo" function
    // to tell it, that we are looking for a IPv4 TCP Connection.
    struct addrinfo hints;
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;          // We are targeting IPv4
    hints.ai_protocol = IPPROTO_TCP;    // We are targeting TCP
    hints.ai_socktype = SOCK_STREAM;    // We are targeting TCP so its SOCK_STREAM

    // Aquiring of the IPv4 address of a host using the newer
    // "getaddrinfo" function which outdated "gethostbyname".
    // It will search for IPv4 addresses using the TCP-Protocol.
    struct addrinfo* targetAdressInfo = NULL;
    DWORD getAddrRes = getaddrinfo("www.google.com", NULL, &hints, &targetAdressInfo);
    if (getAddrRes != 0 || targetAdressInfo == NULL)
    {
        cout << "Could not resolve the Host Name" << endl;
        system("pause");
        WSACleanup();
        return -1;
    }

    // Create the Socket Address Informations, using IPv4
    // We dont have to take care of sin_zero, it is only used to extend the length of SOCKADDR_IN to the size of SOCKADDR
    SOCKADDR_IN sockAddr;
    sockAddr.sin_addr = ((struct sockaddr_in*) targetAdressInfo->ai_addr)->sin_addr;    // The IPv4 Address from the Address Resolution Result
    sockAddr.sin_family = AF_INET;  // IPv4
    sockAddr.sin_port = htons(80);  // HTTP Port: 80

    // We have to free the Address-Information from getaddrinfo again
    freeaddrinfo(targetAdressInfo);

    // Creation of a socket for the communication with the Web Server,
    // using IPv4 and the TCP-Protocol
    SOCKET webSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (webSocket == INVALID_SOCKET)
    {
        cout << "Creation of the Socket Failed" << endl;
        system("pause");
        WSACleanup();
        return -1;
    }

    // Establishing a connection to the web Socket
    cout << "Connecting...\n";
    if(connect(webSocket, (SOCKADDR*)&sockAddr, sizeof(sockAddr)) != 0)
    {
        cout << "Could not connect";
        system("pause");
        closesocket(webSocket);
        WSACleanup();
        return -1;
    }
    cout << "Connected.\n";

    // Sending a HTTP-GET-Request to the Web Server
    const char* httpRequest = "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n";
    int sentBytes = send(webSocket, httpRequest, strlen(httpRequest),0);
    if (sentBytes < strlen(httpRequest) || sentBytes == SOCKET_ERROR)
    {
        cout << "Could not send the request to the Server" << endl;
        system("pause");
        closesocket(webSocket);
        WSACleanup();
        return -1;
    }

    // Receiving and Displaying an answer from the Web Server
    char buffer[10000];
    ZeroMemory(buffer, sizeof(buffer));
    int dataLen;
    while ((dataLen = recv(webSocket, buffer, sizeof(buffer), 0) > 0))
    {
        int i = 0;
        while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
            cout << buffer[i];
            i += 1;
        }
    }

    // Cleaning up Windows Socket Dependencies
    closesocket(webSocket);
    WSACleanup();

    system("pause");
    return 0;
}

Verweise:

Verfall von gethostbyname

Rückgabewert von Socket ()

Rückgabewert von send ()


7

C ++ bietet keine Möglichkeit, dies direkt zu tun. Es würde ganz davon abhängen, welche Plattformen und Bibliotheken Sie haben.

Im schlimmsten Fall können Sie die boost :: asio-Bibliothek verwenden, um eine TCP-Verbindung herzustellen, die HTTP-Header (RFC 2616) zu senden und die Antworten direkt zu analysieren. Mit Blick auf Ihre Anwendungsanforderungen ist dies einfach genug.



@ Andrew: Wenn Ihr "Es tut" das Sybreon anspricht, bietet "C ++ keine Möglichkeit, es direkt zu tun". Dann ist die verknüpfte Antwort ungültig, da sie eine Möglichkeit zeigt, dies mithilfe von Systemspezifikationen zu tun.
Sebastian Mach

@SebastianMach Ich meine, es tut es aber. Importieren Sie einfach eine vom System bereitgestellte Bibliothek und rufen Sie eine Funktion auf, die die Aufgabe für Sie erledigt. Vergleichen Sie das mit allen anderen c ++ - Optionen und es ist entweder sehr schwierig oder es wird Code von Drittanbietern verwendet. Ich halte das für ziemlich direkt.
Andrew

1
@ Andrew: Es ist nur unter Windows "vom System bereitgestellt". Auf anderen Systemen ist das anders. Und es hat nichts mit "C ++ bietet keine Möglichkeit, es direkt zu tun" zu tun, was wirklich bedeutet "Der C ++ - Standard nicht".
Sebastian Mach

@SebastianMach Ja, aber das ist auch subjektiv, da c ++ auch auf Telefonen, Tablets, Mikrocontrollern usw. ausgeführt wird. Wenn nicht jedes einzelne Gerät oder Betriebssystem problemlos einige Funktionen in c ++ unterstützt, nennen wir es nicht direkt von c ++ bereitgestellt? OP hat nicht "c ++ standard" gesagt, sondern nur c ++. Diese Antworten bieten Linux- und Windows-Lösungen, da Sie diese normalerweise für so etwas verwenden würden. Es ist also keine Linux-Lösung, aber ja, sie wird direkt von einem großen Betriebssystem bereitgestellt.
Andrew

6

Hier ist ein Code, der funktioniert, ohne dass eine Bibliothek eines Drittanbieters verwendet werden muss: Definieren Sie zuerst Ihr Gateway, Ihren Benutzer, Ihr Kennwort und alle anderen Parameter, die Sie an diesen bestimmten Server senden müssen.

#define USERNAME "user"
#define PASSWORD "your password"
#define GATEWAY "your gateway"

Hier ist der Code selbst:

HINTERNET hOpenHandle, hResourceHandle, hConnectHandle;
const TCHAR* szHeaders = _T("Content-Type:application/json; charset=utf-8\r\n");


hOpenHandle = InternetOpen(_T("HTTPS"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hOpenHandle == NULL)
{
    return false;
}


hConnectHandle = InternetConnect(hOpenHandle,
    GATEWAY,
    INTERNET_DEFAULT_HTTPS_PORT,
    NULL, NULL, INTERNET_SERVICE_HTTP,
    0, 1);

if (hConnectHandle == NULL)
{
    InternetCloseHandle(hOpenHandle);
    return false;
}


hResourceHandle = HttpOpenRequest(hConnectHandle,
    _T("POST"),
    GATEWAY,
    NULL, NULL, NULL, INTERNET_FLAG_SECURE | INTERNET_FLAG_KEEP_CONNECTION,
    1);

if (hResourceHandle == NULL)
{
    InternetCloseHandle(hOpenHandle);
    InternetCloseHandle(hConnectHandle);
    return false;
}

InternetSetOption(hResourceHandle, INTERNET_OPTION_USERNAME, (LPVOID)USERNAME, _tcslen(USERNAME));
InternetSetOption(hResourceHandle, INTERNET_OPTION_PASSWORD, (LPVOID)PASSWORD, _tcslen(PASSWORD));

std::string buf;
if (HttpSendRequest(hResourceHandle, szHeaders, 0, NULL, 0))
{
    while (true)
    {
        std::string part;
        DWORD size;
        if (!InternetQueryDataAvailable(hResourceHandle, &size, 0, 0))break;
        if (size == 0)break;
        part.resize(size);
        if (!InternetReadFile(hResourceHandle, &part[0], part.size(), &size))break;
        if (size == 0)break;
        part.resize(size);
        buf.append(part);
    }
}

if (!buf.empty())
{
    // Get data back
}

InternetCloseHandle(hResourceHandle);
InternetCloseHandle(hConnectHandle);
InternetCloseHandle(hOpenHandle);

Das sollte in einer Win32-API-Umgebung funktionieren.

Hier ist ein Beispiel .


Was soll ich für das Gateway setzen? Es gibt kein verdammtes Gateway ... Win API ist so schlecht.
Tomáš Zato - Wiedereinsetzung Monica

1
"Gateway" ist nur ein allgemeines Wort für die vom Dienstanbieter bereitgestellte URI ( en.wikipedia.org/wiki/Uniform_Resource_Identifier ). Dies hat nichts mit Windows zu tun.
Michael Haephrati

Ah danke. Ich habe nie gehört, dass dieser Ausdruck für URLs verwendet wird, also hat mich das irgendwie verwirrt. Danke für die Klarstellung.
Tomáš Zato - Wiedereinsetzung Monica

Ok, ich habe den Code getestet und Ihr Beispiel passt nicht zusammen. InternetConnectGibt null zurück, wenn die vollständige URL angegeben ist, gibt jedoch einen Wert ungleich Null zurück, wenn nur der Domänenname angegeben wird. Wann / wo verwende ich die vollständige URL, um die Seite zu erhalten, die ich herunterladen möchte?
Tomáš Zato - Wiedereinstellung Monica

Verwenden Sie InternetOpenUrl () anstelle von InternetConnect (), wenn Sie url
Al Po

4

Aktualisierte Antwort für April 2020:

Ich habe in letzter Zeit viel Erfolg mit cpp-httplib (sowohl als Client als auch als Server) gehabt . Es ist ausgereift und sein ungefährer Single-Threaded-RPS liegt bei 6k.

Auf dem neuesten Stand gibt es ein wirklich vielversprechendes Framework, das 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 antreibt der Planet, Scylladb ).

Das cpv-Framework ist jedoch noch relativ unausgereift. Daher empfehle ich für die meisten Anwendungen cpp-httplib.

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


Danke, werde es vielleicht in naher Zukunft versuchen;)
Hack06

Ich mag den 1-Datei-Ansatz (5K-Zeilen sind in Ordnung) von cpp-httplib sehr. Haben Sie eine Vorstellung von der Leistung?
Hack06

1
@ Hack06 Der grobe Benchmark war ungefähr 6000 Anfragen pro Sekunde (RPS).
Homer6

3

C und C ++ haben keine Standardbibliothek für HTTP oder Socket-Verbindungen. Im Laufe der Jahre wurden einige tragbare Bibliotheken entwickelt. Am weitesten verbreitet ist, wie andere gesagt haben, libcurl .

Hier ist eine Liste von Alternativen zu libcurl (von der libcurl-Website).

Für Linux ist dies auch ein einfacher HTTP-Client. Sie könnten Ihren eigenen einfachen HTTP-GET-Client implementieren, dies funktioniert jedoch nicht, wenn Authentifizierung oder Weiterleitungen erforderlich sind oder wenn Sie hinter einem Proxy arbeiten müssen. Für diese Fälle benötigen Sie eine vollständige Bibliothek wie libcurl.

Für Quellcode mit libcurl kommt dies dem am nächsten, was Sie wollen (Libcurl hat viele Beispiele ). Schauen Sie sich die Hauptfunktion an. Der HTML-Inhalt wird nach einer erfolgreichen Verbindung in den Puffer kopiert. Ersetzen Sie einfach parseHtml durch Ihre eigene Funktion.


3

Sie können die embeddedRest- Bibliothek verwenden. Es ist eine leichte Nur-Header-Bibliothek. Es ist also einfach, es in Ihr Projekt aufzunehmen, und es erfordert keine Kompilierung, da keine .cppDateien darin enthalten sind.

Beispiel readme.mdvon repo anfordern :

#include "UrlRequest.hpp"

//...

UrlRequest request;
request.host("api.vk.com");
const auto countryId=1;
const auto count=1000;
request.uri("/method/database.getCities",{
    {"lang","ru"},
    {"country_id",countryId},
    {"count",count},
    {"need_all","1"},
});
request.addHeader("Content-Type: application/json");
auto response=std::move(request.perform());
if(response.statusCode()==200){
  cout<<"status code = "<<response.statusCode()<<", body = *"<<response.body()<<"*"<<endl;
}else{
  cout<<"status code = "<<response.statusCode()<<", description = "<<response.statusDescription()<<endl;
}

Kompiliert nicht auf Win32: /
uhfocuz

@uhfocuz die lib ist für iOS und Android geschrieben. Aber ich kann Ihnen beim Kompilieren für Win32 helfen. Es ist nicht zu schwierig
fnc12

Ich liebe, wie leicht es für meinen Gebrauch ist, es ist gut auf meinem Mac kompiliert, aber unter Windows sind die Bibliotheken anders, als Sie es nicht haben netdb.husw. Ich hätte gerne Hilfe, ja
uhfocuz

@uhfocuz alles was Sie tun müssen, ist Bedingungen wie #ifdef _WIN32hinzuzufügen und dort Windows-spezifischen Code hinzuzufügen. Schauen Sie hier - es gibt keinen großen Unterschied zwischen Unix-Sockets und Windows-Sockets. Ich sehe zwei Hauptunterschiede: 1) WSAStartupzuerst anrufen und 2) closesocketanstelle vonclose
fnc12

@uhfocuz Bitte erstellen Sie ein Problem in meinem Repo - Ich werde Win32-Unterstützung hinzufügen, sobald ich genug Zeit habe
FNC12

3

Das HTTP-Protokoll ist sehr einfach, daher ist es sehr einfach, einen HTTP-Client zu schreiben. Hier ist eine

https://github.com/pedro-vicente/lib_netsockets

Es verwendet HTTP GET, um eine Datei von einem Webserver abzurufen. Sowohl Server als auch Datei sind Befehlszeilenparameter. Die entfernte Datei wird in einer lokalen Kopie gespeichert.

Haftungsausschluss: Ich bin der Autor

BEARBEITEN: URL bearbeitet


Die angegebene URL ist ungültig.
Shravan40

3

Beachten Sie, dass hierfür libcurl, Windows.h oder WinSock nicht erforderlich sind! Keine Kompilierung von Bibliotheken, keine Projektkonfiguration usw. Ich habe diesen Code in Visual Studio 2017 c ++ unter Windows 10:

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

#include <urlmon.h>
#include <sstream>

using namespace std;

...

IStream* stream;
//Also works with https URL's - unsure about the extent of SSL support though.
HRESULT result = URLOpenBlockingStream(0, "http://google.com", &stream, 0, 0);
if (result != 0)
{
    return 1;
}
char buffer[100];
unsigned long bytesRead;
stringstream ss;
stream->Read(buffer, 100, &bytesRead);
while (bytesRead > 0U)
{
    ss.write(buffer, (long long)bytesRead);
    stream->Read(buffer, 100, &bytesRead);
}
stream.Release();
string resultString = ss.str();

Ich habe gerade herausgefunden, wie das geht, da ich ein einfaches API-Zugriffsskript wollte. Bibliotheken wie libcurl verursachten mir alle möglichen Probleme (selbst wenn ich den Anweisungen folgte ...), und WinSock ist einfach zu niedrig und kompliziert .

Ich bin mir nicht ganz sicher, ob der gesamte IStream-Lesecode (insbesondere die while-Bedingung - Sie können ihn gerne korrigieren / verbessern), aber hey, es funktioniert , problemlos! (Es macht für mich Sinn, dass dies in Ordnung ist , da ich einen blockierenden (synchronen) Aufruf verwendet habe. Das bytesReadwäre immer> 0U, bis der Stream ( ISequentialStream ?) Gelesen ist, aber wer weiß.)

Siehe auch: Referenz zu URL-Monikern und asynchronen steckbaren Protokollen


Es wurde herausgeschnitten, aber nach ziemlich viel Erfahrung in C ++ werde ich zu meiner ursprünglichen Behauptung stehen, dass dies wahrscheinlich der einfachste Weg ist, wie Sie jemals in C ++ so etwas tun können ... (At am wenigsten für jetzt ...)
Andrew

Ich habe gerade URLOpenBlockingStream mit ein paar URLs von badssl.com getestet (ziemlich praktisch), und dieser Vorgang schlägt fehl, wenn das SSL-Zertifikat fehlerhaft ist. In jedem Fall, den ich getestet habe (nur einige wenige), ist die Ausgabe des obigen Codes eine leere Zeichenfolge (keine Stream-Daten). Das ist also ziemlich schön.
Andrew

Ich stimme zu, es ist das einfachste, aber wie würden Sie den http-Antwortcode erhalten?
Robin

@ Robin Ha! Sie wollten die Nachricht und den Antwortcode?! Sie wissen es genauso gut wie ich, außer dass Sie vielleicht eine Antwort finden, wenn Sie sich die Dokumentation und das manuellere URL Monikers-Material ansehen. Ich erinnere mich an jemanden, der Code online veröffentlicht und URLOpenBlockingStream manuell implementiert, was mehr Konfiguration ermöglichen würde. Lassen Sie mich wissen, wenn Sie etwas herausfinden!
Andrew

Es gibt auch Folgendes, das ich gerade gefunden habe: docs.microsoft.com/en-us/windows/desktop/WinInet/… Ich habe keine Ahnung, ob es etwas Gutes ist.
Andrew

2

Hier ist ein (relativ) einfacher C ++ 11-Code, der libCURL verwendet, um den Inhalt einer URL in Folgendes herunterzuladen std::vector<char>:

http_download.hh

# pragma once

#include <string>
#include <vector>

std::vector<char> download(std::string url, long* responseCode = nullptr);

http_download.cc

#include "http_download.hh"

#include <curl/curl.h>
#include <sstream>
#include <stdexcept>

using namespace std;

size_t callback(void* contents, size_t size, size_t nmemb, void* user)
{
  auto chunk = reinterpret_cast<char*>(contents);
  auto buffer = reinterpret_cast<vector<char>*>(user);

  size_t priorSize = buffer->size();
  size_t sizeIncrease = size * nmemb;

  buffer->resize(priorSize + sizeIncrease);
  std::copy(chunk, chunk + sizeIncrease, buffer->data() + priorSize);

  return sizeIncrease;
}

vector<char> download(string url, long* responseCode)
{
  vector<char> data;

  curl_global_init(CURL_GLOBAL_ALL);
  CURL* handle = curl_easy_init();
  curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
  curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, callback);
  curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data);
  curl_easy_setopt(handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
  CURLcode result = curl_easy_perform(handle);
  if (responseCode != nullptr)
    curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, responseCode);
  curl_easy_cleanup(handle);
  curl_global_cleanup();

  if (result != CURLE_OK)
  {
    stringstream err;
    err << "Error downloading from URL \"" << url << "\": " << curl_easy_strerror(result);
    throw runtime_error(err.str());
  }

  return move(data);
}

2

Im Allgemeinen würde ich etwas plattformübergreifendes wie cURL, POCO oder Qt empfehlen. Hier ist jedoch ein Windows-Beispiel!:

#include <atlbase.h>
#include <msxml6.h>
#include <comutil.h> // _bstr_t

HRESULT hr;
CComPtr<IXMLHTTPRequest> request;

hr = request.CoCreateInstance(CLSID_XMLHTTP60);
hr = request->open(
    _bstr_t("GET"),
    _bstr_t("https://www.google.com/images/srpr/logo11w.png"),
    _variant_t(VARIANT_FALSE),
    _variant_t(),
    _variant_t());
hr = request->send(_variant_t());

// get status - 200 if succuss
long status;
hr = request->get_status(&status);

// load image data (if url points to an image)
VARIANT responseVariant;
hr = request->get_responseStream(&responseVariant);
IStream* stream = (IStream*)responseVariant.punkVal;
CImage *image = new CImage();
image->Load(stream);
stream->Release();

2

Wenn Sie nach einer HTTP-Clientbibliothek in C ++ suchen, die auf mehreren Plattformen (Linux, Windows und Mac) unterstützt wird, um Restful-Webdienste zu nutzen. Sie können unten Optionen haben.

  1. QT-Netzwerkbibliothek - Ermöglicht der Anwendung das Senden von Netzwerkanforderungen und das Empfangen von Antworten
  2. C ++ REST SDK - Eine aufstrebende HTTP-Bibliothek eines Drittanbieters mit PPL-Unterstützung
  3. Libcurl - Es ist wahrscheinlich eine der am häufigsten verwendeten http lib in der einheimischen Welt.

1

Obwohl etwas spät. Möglicherweise bevorzugen Sie https://github.com/Taymindis/backcurl .

Sie können damit http-Aufrufe für die mobile C ++ - Entwicklung ausführen. Geeignet für die Entwicklung mobiler Spiele

bcl::init(); // init when using

bcl::execute<std::string>([&](bcl::Request *req) {
    bcl::setOpts(req, CURLOPT_URL , "http://www.google.com",
             CURLOPT_FOLLOWLOCATION, 1L,
             CURLOPT_WRITEFUNCTION, &bcl::writeContentCallback,
             CURLOPT_WRITEDATA, req->dataPtr,
             CURLOPT_USERAGENT, "libcurl-agent/1.0",
             CURLOPT_RANGE, "0-200000"
            );
}, [&](bcl::Response * resp) {
    std::string ret =  std::string(resp->getBody<std::string>()->c_str());
    printf("Sync === %s\n", ret.c_str());
});


bcl::cleanUp(); // clean up when no more using

0

Sie können dazu ACE verwenden:

#include "ace/SOCK_Connector.h"

int main(int argc, ACE_TCHAR* argv[])
{
    //HTTP Request Header
    char* szRequest = "GET /video/nice.mp4 HTTP/1.1\r\nHost: example.com\r\n\r\n"; 
    int ilen = strlen(szRequest);

    //our buffer
    char output[16*1024];

    ACE_INET_Addr server (80, "example.com");
    ACE_SOCK_Stream peer;
    ACE_SOCK_Connector connector;
    int ires = connector.connect(peer, server);
    int sum = 0;
    peer.send(szRequest, ilen);
    while (true)
    {
        ACE_Time_Value timeout = ACE_Time_Value(15);
        int rc = peer.recv_n(output, 16*1024, &timeout);
        if (rc == -1)
        {
            break;
        }
        sum += rc;
    }
    peer.close();
    printf("Bytes transffered: %d",sum);

    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.