Как сделать curl_multi_perform() асинхронно в С++?

Я пришел использовать curl, синхронно выполняя http-запрос. Мой вопрос: как я могу сделать это асинхронно?

Я сделал несколько поисков, которые привели меня к документации интерфейса curl_multi_* из этого question, и этот пример, но он ничего не решал.

Мой упрощенный код:

CURLM *curlm;
int handle_count = 0;
curlm = curl_multi_init();

CURL *curl = NULL;
curl = curl_easy_init();

if(curl)
{
    curl_easy_setopt(curl, CURLOPT_URL, "https://stackoverflow.com/");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
    curl_multi_add_handle(curlm, curl);
    curl_multi_perform(curlm, &handle_count);
}

curl_global_cleanup();

Метод обратного вызова writeCallback не вызывается и ничего не происходит.

Пожалуйста, посоветуйте мне.

EDIT:

Согласно @Remy ниже ответа, я получил это, но кажется, что это не совсем то, что мне действительно нужно. Причина использования цикла по-прежнему является блокирующей. Скажите, пожалуйста, если я ошибаюсь или что-то недопонимаю. Я на самом деле довольно новичок в С++.

Здесь снова мой код:

int main(int argc, const char * argv[])
{
    using namespace std;
    CURLM *curlm;
    int handle_count;
    curlm = curl_multi_init();

    CURL *curl1 = NULL;
    curl1 = curl_easy_init();

    CURL *curl2 = NULL;
    curl2 = curl_easy_init();

    if(curl1 && curl2)
    {
        curl_easy_setopt(curl1, CURLOPT_URL, "https://stackoverflow.com/");
        curl_easy_setopt(curl1, CURLOPT_WRITEFUNCTION, writeCallback);
        curl_multi_add_handle(curlm, curl1);

        curl_easy_setopt(curl2, CURLOPT_URL, "http://google.com/");
        curl_easy_setopt(curl2, CURLOPT_WRITEFUNCTION, writeCallback);
        curl_multi_add_handle(curlm, curl2);

        CURLMcode code;
        while(1)
        {
            code = curl_multi_perform(curlm, &handle_count);

            if(handle_count == 0)
            {
                break;
            }
        }
    }

    curl_global_cleanup();

    cout << "Hello, World!\n";
    return 0;
}

Теперь я могу выполнить 2 HTTP-запроса одновременно. Обратные вызовы вызываются, но их необходимо завершить до выполнения следующих строк. Должен ли я думать о потоке?

Ответ 1

Снова прочтите документацию, особенно эти части:

http://curl.haxx.se/libcurl/c/libcurl-multi.html

Ваше приложение может получить знания из libcurl, если оно хочет получить вызов для передачи данных, так что вам не нужно заняться циклом и вызвать curl_multi_perform (3) как сумасшедший. curl_multi_fdset (3) предлагает интерфейс, с помощью которого вы можете извлечь fd_sets из libcurl для использования в вызовах select() или poll(), чтобы узнать, когда передачам в несколько стека может потребоваться внимание. Это также очень удобно для вашей программы ждать ввода в свои собственные личные дескрипторы файлов одновременно или, возможно, время от времени, если вы этого хотите.

http://curl.haxx.se/libcurl/c/curl_multi_perform.html

Когда приложение обнаружило, что данные, доступные для multi_handle или тайм-аута, истекли, приложение должно вызывать эту функцию для чтения/записи всего, что нужно читать или писать прямо сейчас и т.д. curl_multi_perform() возвращается, как только выполняются чтения/записи. Эта функция не требует, чтобы на самом деле были какие-либо данные, доступные для чтения, или что данные могут быть записаны, их можно назвать на всякий случай. Он напишет количество ручек, которые все еще переносят данные во втором аргументе integer-pointer.

Если количество run_handles изменяется от предыдущего вызова (или меньше количества простых дескрипторов, добавленных в мультирум), вы знаете, что существует одна или несколько передач, которые меньше "работают". Затем вы можете вызвать curl_multi_info_read (3), чтобы получить информацию о каждом отдельном завершенном переносе, а возвращаемая информация включает CURLcode и многое другое. Если добавленный дескриптор не работает очень быстро, он никогда не может считаться run_handle.

Когда run_handles устанавливается на ноль (0) при возврате этой функции, больше не происходит никаких передач.

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

В статье статьи в блоге, которую вы указали, упоминается этот цикл:

Код может использоваться как

Http http;
http: AddRequest (" http://www.google.com ");

//В некоторых циклах обновления каждый кадр
HTTP: Update();

Вы не делаете никаких циклов в своем коде, поэтому ваш обратный вызов не вызывается. Новые данные еще не получены, когда вы вызываете curl_multi_perform() один раз.