18 ответов:
у меня была та же проблема. libcurl действительно полная. Есть обертка C++curlpp это может вас заинтересовать, когда вы просите библиотеку C++. неон еще одна интересная библиотека C, которая также поддерживает WebDAV.
curlpp кажется естественным, если вы используете C++. В исходном дистрибутиве приведено много примеров. Чтобы получить содержимое 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();посмотреть
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); }
в Linux я попробовал cpp-netlib, libcurl, curlpp, urdl, boost::asio и рассмотрел Qt (но отказался от него на основе лицензии). Все они были либо неполными для этого использования, имели неаккуратные интерфейсы, имели плохую документацию, не поддерживались или не поддерживали https.
затем, по предложению https://stackoverflow.com/a/1012577/278976, я попробовал POCO. Жаль, что я не видел этого много лет назад. Вот пример создания HTTP GET запрос:
http://xjia.heroku.com/2011/09/10/learning-poco-get-with-http/
POCO является бесплатным, с открытым исходным кодом (boost license). И нет, у меня нет никакой связи с компанией; мне просто очень нравятся их интерфейсы. Отличная работа, ребята (и девушки).
http://pocoproject.org/download/index.html
надеюсь, это кому-то поможет... мне потребовалось три дня, чтобы опробовать все эти библиотеки.
существует более новая, менее зрелая оболочка завитка разрабатывается под названием C++ Требует. Вот простой запрос 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 глаголов и вариантов скручивания. Там больше документации по использованию здесь.
отказ от ответственности: я хранитель этой библиотеки.
Как вы хотите решение на C++, вы можете использовать Qt. Он имеет класс QHttp, который вы можете использовать.
вы можете проверить docs:
http->setHost("qt.nokia.com"); http->get(QUrl::toPercentEncoding("/index.html"));Qt также имеет гораздо больше к нему, что вы могли бы использовать в общем приложении C++.
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 связанный выше.
вот моя минимальная обертка вокруг cURL, чтобы иметь возможность просто получить веб-страницу в виде строки. Это полезно, например, для модульного тестирования. Это в основном РАИИ обертки вокруг кода.
установите "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; } };
С этим ответом я имею в виду ответ от Software_Developer. Перестроив код, я обнаружил, что некоторые части устаревший (
gethostbyname()) или не предоставлять обработку ошибок (создание сокетов, отправка чего-то) для операции.следующее код windows тестируется с Visual Studio 2013 и Windows 8.1 64-разрядной, а также Windows 7 64-разрядной. Он будет нацелен на соединение IPv4 TCP с веб-сервером www.google.com.
#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; }ссылки:
вы можете проверить C++ REST SDK (кодовое название "Касабланка"). http://msdn.microsoft.com/en-us/library/jj950081.aspx
С помощью C++ REST SDK вы можете более легко подключаться к HTTP-серверам из вашего приложения C++.
пример использования:
#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-это проект Microsoft для облачного взаимодействия клиент-сервер в машинном коде с использованием современного асинхронного дизайна API C++.
C++ не предоставляет никакого способа сделать это напрямую. Это будет полностью зависеть от того, какие платформы и библиотеки у вас есть.
в худшем случае вы можете использовать библиотеку boost::asio для установления TCP-соединения, отправки заголовков HTTP (RFC 2616) и прямого анализа ответов. Глядя на потребности вашего приложения, это достаточно просто сделать.
C и C++ не имеют стандартной библиотеки для HTTP или даже для сокетов. За эти годы были разработаны некоторые портативные библиотеки. Наиболее широко используется, как говорили другие, libcurl.
здесь список альтернатив libcurl (исходя из веб-сайта libcurl).
кроме того, для Linux этой - это простой HTTP-клиент. Вы можете реализовать свой собственный простой HTTP GET клиент, но это не будет работать, если там участвуют ли аутентификация или перенаправления, или если вам нужно работать за прокси-сервером. Для этих случаев вам нужна полноценная библиотека, такая как libcurl.
для исходного кода с libcurl,этой ближе всего к тому, что вы хотите (Libcurl имеет много примеры). Посмотрите на основную функцию. Содержимое html будет скопировано в буфер после успешного подключения. Просто замените parseHtml на свою собственную функцию.
можно использовать embeddedRest библиотека. Это легкая библиотека только для заголовков. Поэтому его легко включить в свой проект, и он не требует компиляции, потому что там нет
запрос от.cppфайлы в ней.readme.mdиз РЕПО:#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; }
вот некоторый (относительно) простой код C++11, который использует libCURL для загрузки содержимого URL в
std::vector<char>:http_download.чч
# 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); }
вообще я бы рекомендовал что-то кросс-платформенное, как 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();
протокол HTTP очень прост, поэтому очень просто написать HTTP-клиент. Вот один
https://github.com/pedro-vicente/lib_netsockets
Он использует HTTP GET для получения файла с веб-сервера, как сервер, так и файл являются параметрами командной строки. Удаленный файл сохраняется в локальной копии.
отказ от ответственности: я автор
Редактировать: Редактировать адрес
обратите внимание, что для этого не требуется libcurl, Windows.h, или WinSock! Никакой компиляции библиотек, без конфигурации проекта и т. д. У меня есть этот код, работающий в Visual Studio 2017 c++ на 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();Я просто понял, как это сделать, так как я хотел простой скрипт доступа к API, библиотеки, такие как libcurl, вызывали у меня всевозможные проблемы (даже когда я следовал указаниям...), а WinSock просто слишком низкоуровневый и сложный.
Я не совсем уверен все это IStream чтение кода (особенно условие while-не стесняйтесь исправлять / улучшать), но эй,он работает, хлопот бесплатно! (Это имеет смысл для меня, так как я использовал блокировка (синхронно) вызова, это нормально, что
bytesReadвсегда будет > 0U, пока поток (ISequentialStream?) закончил чтение, но кто знает.)Читайте также: Моникеры URL и асинхронный подключаемый протокол Ссылка
хотя немного поздно. Вы можете предпочесть https://github.com/Taymindis/backcurl .
Это позволяет делать http-вызов на мобильных c++ разработки. Подходит для разработки мобильных игр
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
вы можете использовать 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; }
Comments