Czy jest jakiś sposób na łatwe wykonanie żądania HTTP w C ++? W szczególności chcę pobrać zawartość strony (API) i sprawdzić zawartość, aby zobaczyć, czy zawiera 1 lub 0. Czy można również pobrać zawartość do łańcucha?
Czy jest jakiś sposób na łatwe wykonanie żądania HTTP w C ++? W szczególności chcę pobrać zawartość strony (API) i sprawdzić zawartość, aby zobaczyć, czy zawiera 1 lub 0. Czy można również pobrać zawartość do łańcucha?
Odpowiedzi:
Miałem ten sam problem. libcurl jest naprawdę kompletny. Istnieje curlpp otoki C ++, który może Cię zainteresować, gdy poprosisz o bibliotekę C ++. neon to kolejna interesująca biblioteka C, która obsługuje również WebDAV .
curlpp wydaje się naturalny, jeśli używasz C ++. W dystrybucji źródłowej podano wiele przykładów. Aby uzyskać treść adresu URL, robisz coś takiego (wyciąg z przykładów):
// 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();
Zobacz examples
katalog w dystrybucji źródłowej curlpp , istnieje wiele bardziej skomplikowanych przypadków, a także prosty kompletny minimalny przy użyciu curlpp.
moje 2 centy ...
os << myRequest.perform();
go myRequest.setOpt( new curlpp::options::WriteStream( &os ) ); myRequest.perform();
dało wyniki. Pamiętaj, aby nie używać http://example.com
, spowoduje to zwrócenie pustej strony. Lepsze wykorzystanie np http://www.wikipedia.org
.
Kod systemu 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;
}
Oto znacznie lepsza implementacja:
#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);
}
GET / HTTP/1.1.1/... etc
)? Jak dowiedzieć się, jak sformatować to, co wysyłam?
Aktualizacja 2020: Mam nową odpowiedź, która zastępuje tę, obecnie 8-letnią, jedną: https://stackoverflow.com/a/61177330/278976
W systemie Linux wypróbowałem cpp-netlib, libcurl, curlpp, urdl, boost :: asio i zastanowiłem się nad Qt (ale odmówiłem na podstawie licencji). Wszystkie z nich były niekompletne do tego zastosowania, miały niechlujne interfejsy, miały słabą dokumentację, były nieobsługiwane lub nie obsługiwały protokołu https.
Następnie, zgodnie z sugestią https://stackoverflow.com/a/1012577/278976 , wypróbowałem POCO. Wow, szkoda, że nie widziałem tego lata temu. Oto przykład tworzenia żądania HTTP GET za pomocą POCO:
https://stackoverflow.com/a/26026828/2817595
POCO jest darmowym, otwartym oprogramowaniem (licencja doładowania). I nie, nie mam żadnych powiązań z firmą; Po prostu bardzo lubię ich interfejsy. Świetna robota chłopaki (i dziewczęta).
https://pocoproject.org/download.html
Mam nadzieję, że to pomoże komuś ... Wypróbowanie wszystkich tych bibliotek zajęło mi trzy dni.
Opracowywane jest nowsze, mniej dojrzałe opakowanie curl o nazwie C ++ Requests . Oto proste żądanie 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;
}
Obsługuje wiele różnych czasowników HTTP i opcji zwijania. Jest więcej dokumentacja Wykorzystanie tutaj .
Oświadczenie: Jestem opiekunem tej biblioteki .
Oto moje minimalne opakowanie wokół cURL, aby móc pobrać stronę internetową jako ciąg znaków. Jest to przydatne na przykład do testowania jednostkowego. Jest to po prostu opakowanie RAII wokół kodu C.
Zainstaluj „libcurl” na swoim komputerze yum install libcurl libcurl-devel
lub jego odpowiedniku.
Przykład użycia:
CURLplusplus client;
string x = client.Get("http://google.com");
string y = client.Get("http://yahoo.com");
Implementacja klasy:
#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;
}
};
libCURL to całkiem dobra opcja dla Ciebie. W zależności od tego, co musisz zrobić, samouczek powinien powiedzieć ci, czego chcesz, szczególnie dla łatwej obsługi. Ale w zasadzie możesz to zrobić, aby zobaczyć źródło strony:
CURL* c;
c = curl_easy_init();
curl_easy_setopt( c, CURL_URL, "www.google.com" );
curl_easy_perform( c );
curl_easy_cleanup( c );
Wierzę, że spowoduje to wydrukowanie wyniku na standardowe wyjście. Jeśli zamiast tego chcesz to obsłużyć - co, jak zakładam, robisz - musisz ustawić CURL_WRITEFUNCTION. Wszystko to opisano w samouczku curl, do którego link znajduje się powyżej.
Jak chcesz rozwiązanie C ++, możesz użyć Qt . Ma klasę QHttp, której możesz użyć.
Możesz sprawdzić dokumenty :
http->setHost("qt.nokia.com");
http->get(QUrl::toPercentEncoding("/index.html"));
Qt ma też o wiele więcej do zaoferowania we wspólnej aplikacji C ++.
QNetworkAccessManager
jest udokumentowany od wersji Qt 4.4; a w Qt 4.8 mówi: QHttp - This class is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.
Myślę, że nadal jest dostępny, jeśli zignorujesz przestarzałe ostrzeżenia.
Możesz sprawdzić C ++ REST SDK (nazwa kodowa „Casablanca”). http://msdn.microsoft.com/en-us/library/jj950081.aspx
Dzięki zestawowi REST SDK C ++ możesz łatwiej łączyć się z serwerami HTTP z aplikacji C ++.
Przykład użycia:
#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 to projekt firmy Microsoft do opartej na chmurze komunikacji klient-serwer w natywnym kodzie przy użyciu nowoczesnego asynchronicznego interfejsu API C ++.
Z tą odpowiedzią odnoszę się do odpowiedzi Software_Developer . Po przebudowaniu kodu odkryłem, że niektóre części są przestarzałe ( gethostbyname()
) lub nie zapewniają obsługi błędów (tworzenie gniazd, wysyłanie czegoś) dla operacji.
Poniższy kod systemu Windows jest testowany z programem Visual Studio 2013 i Windows 8.1 64-bit, a także Windows 7 64-bit. Będzie celować w połączenie IPv4 TCP z serwerem internetowym 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;
}
Bibliografia:
C ++ nie zapewnia żadnego sposobu, aby to zrobić bezpośrednio. Zależy to całkowicie od posiadanych platform i bibliotek.
W najgorszym przypadku możesz użyć biblioteki boost :: asio do nawiązania połączenia TCP, wysłać nagłówki HTTP (RFC 2616) i bezpośrednio parsować odpowiedzi. Patrząc na twoje potrzeby aplikacji, jest to dość proste do zrobienia.
Oto kod, który będzie działał bez potrzeby korzystania z żadnej biblioteki innej firmy: Najpierw zdefiniuj bramę, użytkownika, hasło i wszelkie inne parametry, które musisz wysłać na ten konkretny serwer.
#define USERNAME "user"
#define PASSWORD "your password"
#define GATEWAY "your gateway"
Oto sam kod:
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);
To powinno działać w środowisku Win32 API.
Oto przykład .
InternetConnect
zwraca null, gdy podano pełny adres URL, ale zwraca wartość inną niż null, gdy podana jest tylko nazwa domeny. Więc kiedy / gdzie mam użyć pełnego adresu URL, aby uzyskać stronę, którą chcę pobrać?
Zaktualizowana odpowiedź na kwiecień 2020 r .:
Ostatnio odniosłem duży sukces z cpp-httplib (zarówno jako klient, jak i serwer). Jest dojrzały, a jego przybliżony, jednowątkowy RPS wynosi około 6 tys.
Co więcej, istnieje naprawdę obiecująca platforma, cpv-framework , która może uzyskać około 180 000 RPS na dwóch rdzeniach (i dobrze skaluje się z liczbą rdzeni, ponieważ jest oparta na ramie seastar , która zasila najszybsze DB na planeta, scylladb ).
Jednak szkielet cpv jest nadal stosunkowo niedojrzały; więc do większości zastosowań bardzo polecam cpp-httplib.
To zalecenie zastępuje moją poprzednią odpowiedź (8 lat temu).
C i C ++ nie mają standardowej biblioteki dla HTTP ani nawet dla połączeń gniazd. Z biegiem lat opracowano niektóre biblioteki przenośne. Najpopularniejszym, jak powiedzieli inni, jest libcurl .
Oto lista alternatyw dla libcurl (pochodzących ze strony internetowej libcurl).
Ponadto, dla systemów Linux, to jest to prosty klient HTTP. Możesz wdrożyć własnego prostego klienta HTTP GET, ale to nie zadziała, jeśli w grę wchodzi uwierzytelnianie lub przekierowania albo jeśli potrzebujesz pracy za serwerem proxy. W takich przypadkach potrzebujesz pełnej biblioteki, takiej jak libcurl.
Dla kodu źródłowego z libcurl, to jest najbliżej, co chcesz (libCurl ma wiele przykładów ). Spójrz na główną funkcję. Zawartość html zostanie skopiowana do bufora po udanym połączeniu. Wystarczy zastąpić parseHtml własną funkcją.
Możesz użyć biblioteki embeddedRest . Jest to lekka biblioteka zawierająca tylko nagłówki. Dlatego łatwo jest dołączyć go do swojego projektu i nie wymaga kompilacji, ponieważ nie ma .cpp
w nim plików.
Poproś o przykład readme.md
z repozytorium:
#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;
}
netdb.h
itp więc chciałbym jakąś pomoc Tak
#ifdef _WIN32
i dodać tam kod specyficzny dla systemu Windows. Spójrz tutaj - nie ma dużej różnicy między gniazdami unixowymi a gniazdami Windows. Widzę dwie główne różnice: 1) WSAStartup
najpierw zadzwoń i 2) użyj closesocket
zamiastclose
Protokół HTTP jest bardzo prosty, więc napisanie klienta HTTP jest bardzo proste. Tutaj jest jeden
https://github.com/pedro-vicente/lib_netsockets
Używa HTTP GET, aby pobrać plik z serwera WWW, zarówno serwer, jak i plik są parametrami wiersza poleceń. Plik zdalny jest zapisywany w lokalnej kopii.
Oświadczenie: Jestem autorem
EDYCJA: edytowany adres URL
Pamiętaj, że nie wymaga to libcurl, Windows.h ani WinSock! Brak kompilacji bibliotek, brak konfiguracji projektu itp. Mam ten kod działający w Visual Studio 2017 c ++ na 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();
Właśnie wymyśliłem, jak to zrobić, ponieważ chciałem prostego skryptu dostępu do interfejsu API, biblioteki takie jak libcurl sprawiały mi wiele problemów (nawet gdy postępowałem zgodnie z instrukcjami ...), a WinSock jest po prostu zbyt niski i skomplikowany .
Nie jestem pewien co do całego kodu czytającego IStream (szczególnie warunek while - możesz go poprawić / poprawić), ale hej, to działa , bezproblemowo! (Ma dla mnie sens, że skoro użyłem wywołania blokującego (synchronicznego) , jest w porządku, bytesRead
zawsze będzie to> 0U, dopóki strumień ( ISequentialStream ?) Nie zostanie odczytany, ale kto wie.)
Zobacz także: Monikery URL i odwołanie do protokołu asynchronicznego protokołu wtykowego
Oto niektóre (względnie) prosty kod C ++ 11, który używa libCURL do pobierania zawartości adresu URL do std::vector<char>
:
# pragma once
#include <string>
#include <vector>
std::vector<char> download(std::string url, long* responseCode = nullptr);
#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);
}
Ogólnie polecam coś międzyplatformowego, jak cURL, POCO lub Qt. Oto przykład systemu 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();
Jeśli szukasz biblioteki klienta HTTP w C ++ obsługiwanej na wielu platformach (Linux, Windows i Mac) do korzystania z usług sieciowych Restful. Możesz mieć poniższe opcje.
Chociaż trochę późno. Możesz preferować https://github.com/Taymindis/backcurl .
Pozwala na wykonywanie połączeń http w programowaniu mobilnym c ++. Nadaje się do tworzenia gier mobilnych
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
Możesz użyć ACE, aby to zrobić:
#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;
}