Библиотека libcurl в С++ для работы по HTTP

Библиотека libcurl в С++ для работы по HTTP

KOD

Установка библиотеки

Ubuntu Linux

Достаточно стандартно выполнить команду 

sudo apt-get install curl libcurl3 libcurl3-dev

В дальнейшем собирать исходники надо с опцией -lcurl, например

g++ main.o -o prog -lcurl

Windows

1. Заходим на сайт http://curl.haxx.se/download.html. Качаем версию библиотеки для Win32 - MSVC http://curl.haxx.se/download/l... l-msvc.zip

Распаковываем архив берем от туда все dll- файлы:curllib.dll ;

  1. libeay32.dll ;
  2. openldap.dll ;
  3. ssleay32.dll .

И папку curl ( там заголовойные файлы) находящуюся в папке .\libcurl-7.19.3-win32-ssl-msvc\include 

На данный момент ссылки стали нерабочими, нужно качать исходники и собирать самому из исходников в MSVC.

3. Так же берем curllib.lib из папки .\libcurl-7.19.3-win32-ssl-msvc\lib\Release 

Если у вас MSVC++ используем его, если С++Builder конвертируем файл curllib.lib в curllib-bcb.lib утилитой coff2omf.exe

coff2omf curllib.lib curllib-bcb.lib

Теперь для подключения curl нужно написать

#include "curl/curl.h"
#pragma comment(lib,"curllib.lib")           // для MSVC++
// #pragma comment(lib,"curllib-bcb.lib") // для C++Builder

Для работы программы также может понадобиться libsasl.dll ( из OpenSSL ) и возможно какие-нибудь библиотеки из MSVC++(Если у вас C++Builder).В таком случае при запуске программы из IDE она сразу же будет прекращать работу после без какой либо ошибки. Если же запустить сам exe файл то вылезит окошко указывающее на недостающую библиотеку. Требуемые dll несложно найти и скачать с интернета.

Основные принципы

  1. cUrl предоставляет несколько интерфейсов:Easy  (Простой режим)
  2. Multi  (Многопоточный режим)
  3. Share
При использовании в libcurl "простого" интерфейса вы инициализируете сеанс и получаете handle (часто упоминается как "easy handle"), который вы используете в качестве аргумента в функциях Easy интерфейса. Используйте curl_easy_init, чтобы получить handle.

После получения вы должны установить все нужные параметры в предстоящей передаче, наиболее важным среди которых является URL (передавать что-то без заданного URL невозможно). Вы можете задавать различные функции обратного вызова, которые будут вызываться из библиотеки, при получении данных и т.д. Для всего этого используется curl_easy_setopt.

После того как все настройки окончены, вы сообщаете libcurl выполнение передачи с помощью curl_easy_perform. Она проделает все операции и вернет результат своей работы типа перечисления CURLcode.

После передачи, вы можете установить новые настройки и сделать еще передачу, или, если вы уже закончили, вызовите очистку сессии curl_easy_cleanup. Если вы хотите иметь постоянное подключение, не освобождайте handle сразу, вместо этого выполните другие передачи с использованием этого же handle.

Никогда не используйте один и тот же хендл в разных потоках! (можно сделать синхронизацию, но это сведёт на нет плюсы многопоточности)

Простой пример

#include <stdio.h>
 
#include "curl/curl.h"
#pragma comment(lib,"curllib-bcb.lib") // Для C++Builder
//#pragma comment(lib,"curllib.lib")    // для VC++
//---------------------------------------------------------------------------
int main()
{
    CURL *  curl_handle = curl_easy_init();
    if(curl_handle)
    {
        // задаем  url адрес
        curl_easy_setopt(curl_handle, CURLOPT_URL, "https://www.пример.ru");
        // выполняем запрос
        CURLcode res = curl_easy_perform(curl_handle);
        // закрываем дескриптор curl
        curl_easy_cleanup(curl_handle);
    }
 
    getchar();
    return 0;
}
//---------------------------------------------------------------------------

В итоге в окне консоли получаем html-код страницы.

CURL *curl_easy_init();

Начинает easy(простую) curl-сессию, возвращает её дескриптор, в случае неудачи NULL.

Каждому вызову такой ф-ции должен соответствовать вызов ф-ции

void curl_easy_cleanup(CURL * curl);

для завершении работы.

curl_easy_setopt(CURL *curl, CURLoption option, parameter);

Задает соответствующего поведение через установку опций, возвращает CURLE_OK (0) если успешно, в противном случае код ошибки определенный константами в файле curl/curl.h.

Опция CURLOPT_URL относится NETWORK-опциям и задает url- адрес. Этот параметр должен иметь вид согласно RFC 3986 формата: "scheme://host:port/path"

curl_easy_perform(CURL *curl);

Выполняет отправку запроса на сервер и возвращает CURLE_OK в случае успеха, в противном случае код ошибки.

Заголовки.

Заголовки запроса можно также установить с помощью опций, но в зависимости от версии libcurl, константы определяющие опции могут отличаться. 

curl_easy_setopt(curl_handle, CURLOPT_USERAGENT,"Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20100101 Firefox/16.0");
curl_easy_setopt(curl_handle, CURLOPT_ENCODING, "gzip,deflate"); // если curl скомпилина вместе с gzip 
// curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPALIVE , 1);  // не нашло такой опции в версии 7.19.3
// curl_easy_setopt(curl_handle, CURLOPT_REFERER,"http://some.com"); // yстанавливает referer
curl_easy_setopt(curl_handle, CURLOPT_AUTOREFERER,1);// автоматически заполняет поле referer

Если установить

curl_easy_setopt(curl_handle, CURLOPT_HEADER, 1);

то заголовки ответа сервера будут отображаться в месте с html-кодом страницы (заголовок + тело)

Обработка ошибок.

В случае возникновения ошибки при выполнении функции curl_easy_perform() можно получить её описание с помощью: 

const char *curl_easy_strerror(CURLcode errornum);

Эта функция возвращает строку с описанием кода ошибки CURLcode указанным в аргументе:

res = curl_easy_perform(curl_handle);
if(res != CURLE_OK)
     printf( "curl_easy_perform() failed: %s\n", curl_easy_strerror(res) );

Так же есть возможность получить сообщение об ошибке из буфера ошибок, для этого нужно включить параметр CURLOPT_ERRORBUFFER с помощью ф-ции curl_easy_setopt() указать буфер.

static char ErrorBuffer[CURL_ERROR_SIZE]; // размер определяется константой curl
//...
curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errorBuffer); // указывает буфер ошибок
//...
CURLcode res = curl_easy_perform(curl_handle);
if(res != CURLE_OK)
     cout<<"Error!"<<ErrorBuffer<< endl;

Загрузка в буфер.

По умолчанию curl выводит данные в stdout т.е. в окно консоли. Для того что бы сохранить данные в отдельном буфере нужно указать этот буфер в опции CURLOPT_WRITEDATA и callback функцию которая будет записывать туда данные при их приёме с помощью опции CURLOPT_WRITEFUNCTION.

Функция должна иметь вид:

size_t function( char *ptr, size_t size, size_t nmemb, void* userdata);

char * ptr - указатель на принимаемые данные.

size_t size - размер принимамого блока данных

size_t nmemb - общее количество блоков данных.

void* userdata - это параметр опции CURLOPT_WRITEDATA, в который производится запись - наш буфер.

Функция должна возвращать количество обработанных байт ( size*nmemb ). Если это количество будет отличаться от суммы, полученной на входе вашей функции, то будет отдан сигнал об ошибке в библиотеке. Это можно использовать для прервания передачи, с возвращемым значением CURLE_WRITE_ERROR.

Функция может вернуть значение CURL_WRITEFUNC_PAUSE, которое приведет к приостановке записи в этом соединении. 

В качестве буфера можно использовать контейнер или поток STL что упростит задачу.

Для примера использование std::string :

//----------------------------------------------------------------------------
#include <string>
#include <iostream>
 
#include "curl/curl.h"
#pragma comment(lib,"curllib-bcb.lib") // Для C++Builder
//#pragma comment(lib,"curllib.lib")    // для VC++
//----------------------------------------------------------------------------
static size_t write_data(char *ptr, size_t size, size_t nmemb, string* data)
{
    if (data)
    {
        data->append(ptr, size*nmemb);
        return size*nmemb;
    }
    else 
    return 0;  // будет ошибка
}
//-----------------------------------------------------------------------------
int main()
{
    CURL *curl_handle;
    curl_handle = curl_easy_init();
 
    if (curl_handle)
    {
        curl_easy_setopt(curl_handle, CURLOPT_URL, "google.com");
 
    std::string content;
        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writer);
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &content);
 
        CURLcode res = curl_easy_perform(curl_handle);
        if (res)  std::cout << content << std::endl;
        else      std::cerr << curl_easy_strerror(res) << std::endl;
 
        curl_easy_cleanup(curl_handle);
    }
 
    getchar();
    return 0;
}
//-----------------------------------------------------------------------------

Загрузка в файл

Следующий пример показывает как можно сохранить тело ответа сервера в один в файл, а заголовок в другой.

#include <string>
#include <iostream>
 
#include "curl/curl.h"
#pragma comment(lib,"curllib-bcb.lib")
//---------------------------------------------------------------------------
size_t write_data( char *ptr, size_t size, size_t nmemb, FILE* data)
{
    return fwrite(ptr, size, nmemb, data);
}
//---------------------------------------------------------------------------
int main()
{
    // Открываем файлы для заголовка и тела
 
    const std::string header_filename= "head.txt";
    const std::string body_filename  = "body.html";
 
    FILE *header_file= fopen(header_filename.c_str(),"w");
    if (header_file == NULL) 
    return -1;
 
    FILE *body_file =  fopen(body_filename.c_str(),"w");
    if (body_file == NULL)  
    return -1;
 
    // Выполняем  запрос
    CURL *curl_handle = curl_easy_init();
    if(curl_handle)
    {
    const std::string url= "https://www.пример.ru";
        curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
 
        // сохраняем тело
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, body_file);
        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
 
        // сохраняем заголовок
        curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, header_file);
 
        CURLcode res = curl_easy_perform(curl_handle);
        if(res != CURLE_OK)
            std::cout<< "curl_easy_perform() failed: %s\n" << curl_easy_strerror(res) std::endl;
        curl_easy_cleanup(curl_handle);
    }
 
    std::cout<< "\nDone!"<<std::endl;
    getchar();
    return 0;
}
//--------------------------------------------------------------------------

Перенаправление ( редирект ). 

Для автоматического перехода на перенаправляемую страницу необходимо установить опцию CURLOPT_FOLLOWLOCATION в 1

curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);

Для того что бы ограничить количество перенаправлений нужно установить опцию CURLOPT_MAXREDIRS

её параметр указывает их максимальное количество

curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10); //  останавливаться после 10-ого редиректа

Report Page