C ++로 HTTP 요청을 어떻게합니까?


258

C ++로 HTTP 요청을 쉽게 만들 수있는 방법이 있습니까? 특히, 페이지의 내용 (API)을 다운로드하고 내용에 1 또는 0이 포함되어 있는지 확인하고 싶습니다. 내용을 문자열로 다운로드 할 수도 있습니까?


1
아니요. 현재 언어 또는 네트워킹을위한 표준 라이브러리를 통해 기본적으로 지원되지 않습니다. 그러나 네트워킹 TS N4370이 있습니다. 나는 또한 도서관 추천을 끌어 들이기 때문에이 질문을 VTC했습니다.

BoostBeast는 어떻습니까?
twocrush

답변:


249

나는 같은 문제가 있었다. libcurl 은 정말 완전합니다. C ++ 라이브러리를 요청할 때 관심을 가질 수 있는 C ++ 래퍼 curlpp 이 있습니다. neonWebDAV 를 지원하는 또 다른 흥미로운 C 라이브러리입니다 .

C ++를 사용하면 curlpp가 자연스럽게 보입니다. 소스 배포에 많은 예제가 제공됩니다. URL의 내용을 얻으려면 다음과 같이하십시오 (예에서 추출) :

// 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();

curlpp 소스 배포판examples디렉토리를 참조하십시오 . curlpp를 사용 하는 간단한 완전한 최소 디렉토리 뿐만 아니라 더 복잡한 경우가 많이 있습니다.

내 2 센트 ...


1
최신 버전은 mac ..에서 깨진 것 같습니다. 라이브러리로 링크하면 config.h에 문제가 발생합니다.
eugene

1
글쎄, 나는 위를 컴파일 할 수 없었다. 그러나로 교체 os << myRequest.perform();하면 myRequest.setOpt( new curlpp::options::WriteStream( &os ) ); myRequest.perform();결과가 나왔습니다. 를 사용하지 마십시오 http://example.com. 빈 페이지가 반환됩니다. 더 나은 사용 예 : http://www.wikipedia.org.
Zane

4
MSVS에서 curlpp를 어떻게 구축합니까? 나는 그것을 작동시킬 수 없다 :(
mr5

2
@ ryan-sam의 최신 편집 내용에 동의하지 않습니다. 주어진 라이브러리가 "HTTP 및 WebDAV 작업"을 위해 명시 적으로 만들어 졌기 때문에 웹 개발이 아니라 "webdav"를 작성하는 것이 저자의 의도였습니다.
Bostrot

2
@ bostrot : 그렇습니다. 나는 되돌아 가서 링크를 추가했는데 사람들은 내가 webdev를 썼다고 생각했다. 이 얼마나 유감 :)
신경

115

Windows 코드 :

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

훨씬 나은 구현은 다음과 같습니다.

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

Dev-C ++ 버전 4.9.9.2로 컴파일하는 Windows Vista에서이 코드를 사용해 보았습니다. [Linker error]`WSAStartup @ 8 '에 대한 정의되지 않은 참조
Expanding-Dev

4
@ Expanding-Dev Only MSVC (시각 스튜디오)는 "pragma comment"를 이해합니다. 다른 것을 사용하는 경우 다른 라이브러리처럼 "ws2_32.lib"를 수동으로 연결해야합니다.
Navin

24
@JuanLuisSoldi 난 당신이 정말이 코드의 "아름다움"을 감상하기 위해 Windows 개발자가 필요하다고 생각합니다 ...
static_rtti

여기에 무엇을 받아야합니까 (recv를 사용하여)? 출력으로 많은 횡설수설을 받고 있습니다. 또한 왜 송신 버퍼에 수행 한 작업을 넣었 GET / HTTP/1.1.1/... etc습니까 (예 :) ? 보내는 내용을 형식화하는 방법을 어떻게 알 수 있습니까?
LazerSharks

43

업데이트 2020 : 나는 이것을 대체하는 새로운 대답을 얻었습니다. 현재 8 세입니다 .https : //stackoverflow.com/a/61177330/278976

Linux에서는 cpp-netlib, libcurl, curlpp, urdl, boost :: asio를 시도하고 Qt를 고려했지만 라이센스에 따라 거절했습니다. 이 모두는이 용도로는 불완전했거나, 인터페이스가 느슨하거나, 문서가 열악하거나, 유지 관리되지 않았거나 https를 지원하지 않았습니다.

그런 다음 https://stackoverflow.com/a/1012577/278976 의 제안에 따라 POCO를 시도했습니다. 와우, 나는 몇 년 전에 본 적이 있기를 바랍니다. 다음은 POCO로 HTTP GET 요청을 작성하는 예입니다.

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

POCO는 무료이며 오픈 소스입니다 (부스트 라이센스). 그리고 아뇨, 저는 회사와 아무런 관련이 없습니다. 나는 그들의 인터페이스를 정말로 좋아한다. 훌륭한 직업들 (그리고 여자들).

https://pocoproject.org/download.html

이것이 누군가를 돕기를 바랍니다 ...이 라이브러리를 모두 시험해 보는 데 3 일이 걸렸습니다.



2
방금 제안에 Poco를 다운로드했습니다. 나는 STL을 기반으로하고 그것을 많이 다시 쓰는 것이 아니라 부스트하는 가벼운 것을 선호합니다. 또한 나는 CppUnit의 팬이 아니며 특히 빌드로 실행되는 테스트를 싫어하며 빌드 할 때 라이브러리를 테스트 할 필요가 없습니다.
CashCow

조금 큽니다. 그러나 configure를 사용하여 테스트 및 샘플 (또는 공유 라이브러리) 빌드를 비활성화 할 수 있습니다 (예 : --no-tests 또는 --no-samples 또는 --no-sharedlibs). 참조 github.com/pocoproject/poco/blob/develop/configure
Homer6

고마워 어쨌든 내가해야 할 일을 완수하는 데 관심이 있기 때문에 원합니다. 그리고 JSON 구문 분석이있어서 라이브러리를 얻은 HTTP 요청을 보낸 후에해야합니다.
CashCow

얼마 전 이었지만, 지금은 링크가 작동하지 않는 것을 알 수 있도록하기 위해서입니다. github 저장소도 제거 된 것처럼 보입니다 ...
Hack06

33

C ++ Requests 라고하는 덜 성숙 된 컬 래퍼가 개발되었습니다 . 간단한 GET 요청은 다음과 같습니다.

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

다양한 HTTP 동사 및 컬 옵션을 지원합니다. 더 많은 사용 설명서가 있습니다 .

면책 조항 : 나는이 도서관의 관리자입니다 .


10
어제 CppCon 2015 번개 대화에 참석했습니다. 대화와 도서관 모두 잘했습니다. 저는 특히 "사람을위한 컬"디자인 철학을 좋아합니다.
U007D

안녕하세요, 나는이 게시물을 보았습니다. 일반적인 방법보다 쉬운 C ++ HTTP 요청을 찾고 있습니다. 그러나 실제로 라이브러리에 익숙하지는 않으며 Visual Studio C ++ 프로젝트에 라이브러리를 포함시키는 방법을 모르겠습니다. 어딘가에 대한 설명이 있습니까? 나는 그것이 도서관에만 국한된 것이 아니라 오히려 일반적으로 내 앞에서 무엇을해야하는지 실제로 모른다는 느낌이 든다.
Sossenbinder

2
@Sossenbinder, CMake에 익숙해지면이 프로젝트를 사용하여 Visual Studio 빌드 파일을 생성 할 수 있습니다. appveyor 구성 파일이 작업을 수행하는 방법에 대한 대략적인 예제를 포함하고 있습니다.
huu

2
멋져 보이지만 건물은 지옥이므로, lib는 쓸모가 없습니다. 패키지 관리자에 의존 할 수 없으며 (외부 적으로
dep

그것이 당신이하는 방법입니다. 이 질문을 두 번째로 가장 많이
찬성 된

17

다음은 웹 페이지를 문자열로 가져올 수 있도록 cURL을 둘러싼 최소 래퍼입니다. 예를 들어 단위 테스트에 유용합니다. 기본적으로 C 코드 주위의 RAII 래퍼입니다.

머신에 "libcurl"을 설치하십시오 yum install libcurl libcurl-devel.

사용 예 :

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

클래스 구현 :

#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 은 당신에게 아주 좋은 옵션입니다. 무엇을해야하는지에 따라, 튜토리얼 은 특히 ​​손쉬운 조작을 위해 원하는 것을 알려줍니다. 그러나 기본적으로 페이지 소스를 확인하기 위해이 작업을 수행 할 수 있습니다.

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

나는 이것이 결과가 stdout으로 인쇄되게 할 것이라고 믿는다. 대신 처리하려는 경우 CURL_WRITEFUNCTION을 설정해야합니다. 이 모든 것은 위에 링크 된 curl 튜토리얼에서 다룹니다.


16

C ++ 솔루션을 원한다면 Qt를 사용할 수 있습니다 . 사용할 수있는 QHttp 클래스가 있습니다.

당신은 문서 를 확인할 수 있습니다 :

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

Qt는 또한 일반적인 C ++ 앱에서 사용할 수있는 많은 기능을 제공합니다.


4
QHttp가 Qt 4.6 이상 버전에서 QNetworkAccessManager 및 관련 클래스로 대체되었다고 생각합니다.
juzzlin

3
QNetworkAccessManagerQt 4.4부터 문서화되었습니다. Qt 4.8에서는 다음과 같이 말합니다. QHttp - This class is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.더 이상 사용되지 않는 경고를 무시하면 여전히 사용할 수 있다고 생각합니다.
Jesse Chisholm

13

C ++ REST SDK (코드 명 "Casablanca") 를 확인할 수 있습니다 . http://msdn.microsoft.com/en-us/library/jj950081.aspx

C ++ REST SDK를 사용하면 C ++ 앱에서 HTTP 서버에 더 쉽게 연결할 수 있습니다.

사용 예 :

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

C ++ REST SDK는 최신 비동기 C ++ API 설계를 사용하여 원시 코드로 클라우드 기반 클라이언트-서버 통신을위한 Microsoft 프로젝트입니다.


10

이 답변에서는 Software_Developer답변을 참조합니다 . 코드를 다시 작성하면 일부 부분이 더 이상 사용되지gethostbyname() 않거나 ( ) 오류 처리를 제공하지 않는 것으로 나타났습니다 (소켓 생성, 전송)를 .

다음 Windows 코드 는 Visual Studio 2013 및 Windows 8.1 64 비트와 Windows 7 64 비트에서 테스트되었습니다. www.google.com 웹 서버와의 IPv4 TCP 연결을 대상으로합니다.

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

참고 문헌 :

gethostbyname 사용 중단

socket ()의 반환 값

send ()의 반환 값


7

C ++은 직접 수행 할 수있는 방법을 제공하지 않습니다. 그것은 당신이 가진 플랫폼과 라이브러리에 전적으로 달려 있습니다.

최악의 경우 boost :: asio 라이브러리를 사용하여 TCP 연결을 설정하고 HTTP 헤더 (RFC 2616)를 보내고 응답을 직접 구문 분석 할 수 있습니다. 응용 프로그램 요구 사항을 살펴보면이 작업은 충분히 간단합니다.


1
적어도 지금은 그렇습니다. :) stackoverflow.com/a/51959694/1599699
Andrew

@Andrew : " 그렇다면 " sybreon의 "C ++가 직접 수행 할 방법을 제공하지 않습니다." 링크 된 답변은 시스템 사양을 사용하여 수행하는 방법을 보여 주므로 유효하지 않습니다.
Sebastian Mach

@SebastianMach 나는 의미한다. 시스템 제공 라이브러리를 가져 와서 함수를 호출하기 만하면됩니다. 다른 모든 C ++ 옵션과 비교하면 실제로 어렵거나 타사 코드를 사용하는 것입니다. 나는 그것이 매우 직접적이라고 생각합니다.
앤드류

1
@Andrew : Windows에서만 "시스템 제공"입니다. 다른 시스템에서는 다릅니다. 그리고 "C ++은 직접 할 수있는 방법을 제공하지 않습니다"와는 아무런 관련이 없습니다. 이는 "C ++ 표준은 그렇지 않습니다"를 의미합니다.
Sebastian Mach

@SebastianMach 네, c ++도 휴대폰 태블릿 마이크로 컨트롤러 등에서 실행되기 때문에 주관적이기도합니다. 모든 단일 장치 나 OS가 c ++의 일부 기능을 쉽게 지원하지 않는 경우 c ++에서 직접 제공하지는 않습니까? OP는 "c ++ 표준"이라고 말하지 않았고 방금 c ++라고 말했습니다. 이 답변은 Linux 및 Windows 솔루션을 제공합니다. 일반적으로 이와 같은 용도로 사용되기 때문입니다. 확실히 이것은 Linux 솔루션이 아니지만 주요 OS에서 직접 제공합니다.
앤드류

6

타사 라이브러리를 사용할 필요없이 작동하는 코드는 다음과 같습니다. 먼저 게이트웨이, 사용자, 비밀번호 및이 특정 서버로 전송해야하는 기타 매개 변수를 정의하십시오.

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

코드 자체는 다음과 같습니다.

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

Win32 API 환경에서 작동합니다.

여기 예가 있습니다.


게이트웨이에 무엇을 넣어야합니까? 망할 게이트웨이가 없습니다 ... Win API가 너무 나쁩니다.
Tomáš Zato – 복원 모니카

1
"게이트웨이"는 서비스 제공 업체가 제공 한 URI ( en.wikipedia.org/wiki/Uniform_Resource_Identifier ) 의 일반적인 단어입니다 . 이것은 Windows와 관련이 없습니다.
Michael Haephrati

아 고마워 나는 그 표현이 URL에 사용될 것이라는 말을 들어 본 적이 없기 때문에 다소 혼란 스럽습니다. 설명해 주셔서 감사합니다.
Tomáš Zato-복원 모니카

좋아, 나는 코드를 테스트했지만 예제가 합산되지 않는다. InternetConnect전체 URL이 제공되면 null을 반환하지만 도메인 이름 만 제공하면 null이 아닌 값을 반환합니다. 그렇다면 언제 어디에서 전체 URL을 사용하여 다운로드하려는 페이지를 얻을 수 있습니까?
Tomáš Zato-복원 모니카

url을 사용하려면 InternetConnect () 대신 InternetOpenUrl ()을 사용하십시오
Al Po

4

2020 년 4 월 업데이트 된 답변 :

최근에 cpp-httplib (클라이언트 및 서버 모두)를 통해 많은 성공을 거두었습니다 . 성숙하고 대략적인 단일 스레드 RPS는 약 6k입니다.

최첨단 기술에는 두 개의 코어에서 약 180k RPS를 얻을 수있는 가장 유망한 프레임 워크 인 cpv-framework 가 있으며 , 가장 빠른 DB를 구동 하는 seastar 프레임 워크를 기반으로하므로 코어 수에 따라 확장 됩니다. 행성, scylladb ).

그러나 cpv-framework는 여전히 상대적으로 미숙합니다. 따라서 대부분의 경우 cpp-httplib를 적극 권장합니다.

이 권장 사항은 이전 답변 (8 년 전)을 대체합니다 .


감사합니다, 가까운 장래에 시도해 볼 것입니다;)
Hack06

나는 cpp-httplib의 1 파일 (5K 라인은 괜찮습니다) 접근법을 정말로 좋아합니다. 성능에 대한 아이디어가 있습니까?
Hack06

1
@ Hack06 대략적인 벤치 마크는 초당 약 6000 개의 요청 (RPS)입니다.
호머 6

3

C 및 C ++에는 HTTP 또는 소켓 연결을위한 표준 라이브러리가 없습니다. 수년 동안 일부 휴대용 라이브러리가 개발되었습니다. 다른 사람들이 말했듯이 가장 널리 사용되는 것은 libcurl 입니다.

다음은 libcurl의 대안 목록 입니다 (libcurl 웹 사이트에서 제공).

또한, 리눅스, 간단한 HTTP 클라이언트입니다. 고유 한 간단한 HTTP GET 클라이언트를 구현할 수 있지만 인증이나 리디렉션이 있거나 프록시 뒤에서 작업해야하는 경우에는 작동하지 않습니다. 이러한 경우 libcurl과 같은 본격적인 라이브러리가 필요합니다.

libcurl에와 소스 코드의 경우, 이것은 당신이 원하는에 가장 가까운 (libcurl에 많은있다 ). 주요 기능을보십시오. 성공적으로 연결되면 html 컨텐츠가 버퍼에 복사됩니다. parseHtml을 자신의 함수로 바꾸십시오.


3

embeddedRest 라이브러리 를 사용할 수 있습니다 . 가벼운 헤더 전용 라이브러리입니다. 따라서 프로젝트에 쉽게 포함시킬 수 있으며 .cpp파일 이없는 컴파일 원인이 필요하지 않습니다 .

readme.mdrepo 에서 요청 예 :

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

Win32에서 컴파일되지 않습니다 : /
uhfocuz

@uhfocuz lib는 iOS 및 Android 용으로 작성되었습니다. 그러나 Win32 용으로 컴파일하는 데 도움을 줄 수 있습니다. 너무 어렵지 않습니다
fnc12

나는 그것이 나의 사용을 위해 얼마나 가볍고, 그것은 나의 Mac에서 잘 컴파일되었지만 Windows에서 libs는 당신이없는 것처럼 다르 netdb.h므로 도움이 필요합니다
uhfocuz

@uhfocuz 당신이해야 할 일은 같은 조건 #ifdef _WIN32을 추가하고 거기에 윈도우 특정 코드를 추가하는 것입니다. 봐 여기에 - 유닉스 소켓 및 Windows 소켓 사이에 큰 차이가 없습니다. 1) WSAStartup첫 번째 호출 과 2)closesocketclose
fnc12

@uhfocuz 내 repo에 문제를 작성하십시오-충분한 시간이 있으면 win32 지원을 추가합니다
fnc12

3

HTTP 프로토콜은 매우 간단하므로 HTTP 클라이언트를 작성하는 것은 매우 간단합니다. 여기 하나

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

HTTP GET을 사용하여 웹 서버에서 파일을 검색합니다. 서버와 파일은 모두 명령 행 매개 변수입니다. 원격 파일은 로컬 사본에 저장됩니다.

면책 조항 : 나는 저자입니다

수정 : 수정 된 URL


주어진 URL이 유효하지 않습니다.
Shravan40

3

libcurl, Windows.h 또는 WinSock이 필요하지 않습니다. 라이브러리 컴파일, 프로젝트 구성 등이 없습니다.이 코드는 Windows 10의 Visual Studio 2017 c ++에서 작동합니다.

#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();

간단한 API 액세스 스크립트를 원했기 때문에 libcurl과 같은 라이브러리로 인해 모든 종류의 문제가 발생했습니다 (방향을 따랐을 때도 ...). WinSock은 너무 낮고 복잡합니다. .

나는 모든 IStream 읽기 코드 에 대해 잘 모르겠지만 (특히 while 조건-수정 / 개선 할 수 있음을 느낍니다), 이봐, 그것은 작동 하고 번거 로움이 없습니다! (그것은, 내가 그에게 의미가 내가 사용하기 때문에 차단 (동기) 호출 이 그 괜찮 bytesRead항상 것> 0U 스트림까지 ( 대해 ISequentialStream는 ?) 완성 된 존재가 읽을 수 있습니다,하지만 누가 알 겠어.)

참조 : URL 모니 커와 비동기 플러그 프로토콜 참조


그것은 밖으로 편집했지만, C 경험의 공정한 금액 후에 ++, 나는이 것을 내 원래의 주장 대기거야 아마 에서 (당신이 이제까지 C ++에서 이런 종류의 일을 할 수있을 것입니다 가장 쉬운 방법은 ... 최소한 지금은 ...)
Andrew

방금 badssl.com의 URL 몇 개를 사용하여 URLOpenBlockingStream을 테스트했으며 (SSL) 매우 좋지만 이 작업은 실패합니다. 테스트 한 모든 경우 (몇 개만) 위의 코드 출력은 빈 문자열 (스트림 데이터 없음)이됩니다. 꽤 멋지다.
앤드류

나는 그것이 가장 쉬운 것이라고 동의하지만 어떻게 http 응답 코드를 얻을 수 있습니까?
Robin

@ 로빈 하! 메시지 응답 코드를 원하십니까?! 문서를 보거나 더 많은 수동 URL 모니 커 자료를 보면 답을 찾을 수 있다는 점을 제외하고는 당신도 알고 있습니다. URLOpenBlockingStream을 수동으로 구현하여 온라인으로 코드를 게시하는 사람이 더 많은 구성을 허용한다고 생각합니다. 당신이 무언가를 알아내는 경우 알려주십시오!
앤드류


2

다음은 libCURL을 사용하여 URL의 내용을 다음으로 다운로드하는 간단한 C ++ 11 코드입니다 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

일반적으로 cURL, POCO 또는 Qt와 같은 크로스 플랫폼을 권장합니다. 그러나 Windows 예제는 다음과 같습니다.

#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

Restful 웹 서비스를 사용하기 위해 여러 플랫폼 (Linux, Windows 및 Mac)에서 지원되는 C ++에서 HTTP 클라이언트 라이브러리를 찾고있는 경우 아래 옵션을 가질 수 있습니다.

  1. QT 네트워크 라이브러리 -애플리케이션이 네트워크 요청을 보내고 응답을받을 수 있도록합니다.
  2. C ++ REST SDK -PPL을 지원하는 새로운 타사 HTTP 라이브러리
  3. Libcurl- 아마도 아마도 세계에서 가장 많이 사용되는 http lib 중 하나 일 것입니다.

1

조금 늦었지만. https://github.com/Taymindis/backcurl을 선호 할 수 있습니다 .

그것은 당신이 모바일 C ++ 개발에 http 호출을 할 수 있습니다. 모바일 게임 개발에 적합

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

ACE를 사용하여 다음을 수행 할 수 있습니다.

#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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.