web-dev-qa-db-ja.com

C ++でcurl_multi_perform()を非同期に実行するにはどうすればよいですか?

curlを同期的に使用してhttpリクエストを実行するようになりました。私の質問は、どうすれば非同期でそれを行うことができますか?

この 質問 とこれ からcurl_multi_*インターフェースのドキュメントにつながる検索をいくつか行いましたが、何も解決しませんでした。

私の簡略化されたコード:

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は呼び出されず、何も起こりません。

教えてください。

編集:

@Remyの以下の回答によると、私はこれを手に入れましたが、本当に必要なものではないようです。ループを使用している原因は依然としてブロッキングです。私が間違ったことをしているのか、何かを誤解しているのか教えてください。私は実際にはC++にかなり慣れていません。

これが私のコードです:

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リクエストを同時に実行できます。コールバックが呼び出されますが、次の行を実行する前に終了する必要があります。スレッドについて考える必要がありますか?

10
Nhon Nguyen

ドキュメント、特にこれらの部分をもう一度注意深く読んでください。

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

アプリケーションは、データを転送するために呼び出されたいときにlibcurlから知識を取得できるため、ビジーループしてそれを呼び出す必要はありません curl_multi_perform(3) 狂ったように。 curl_multi_fdset(3) は、libcurlからfd_setを抽出してselect()またはpoll()呼び出しで使用し、いつマルチスタックでの転送には注意が必要な場合があります。これにより、プログラムが独自のプライベートファイル記述子への入力を同時に待機したり、必要に応じて時々タイムアウトしたりすることも非常に簡単になります。

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

multi_handleに使用できるデータがあることをアプリケーションが検出した場合、またはタイムアウトが経過した場合、アプリケーションはこの関数を呼び出して、現在読み取りまたは書き込みが可能なものをすべて読み取り/書き込みする必要がありますなど。curl_multi_perform()は、読み取り/書き込みが完了するとすぐに戻ります。この関数は、実際に読み取り可能なデータが存在する必要はなく、データを書き込むことができる必要もありません。万が一の場合に備えて呼び出すことができます。 2番目の引数の整数ポインターにデータを転送するハンドルの数を書き込みます。

running_handlesの量が前の呼び出しから変更された場合(またはマルチハンドルに追加したイージーハンドルの量より少ない場合)、1つまたは転送が多いほど「実行中」は少なくなります。次に、 curl_multi_info_read(3) を呼び出して、完了した個々の転送に関する情報を取得できます。返される情報には、CURLcodeなどが含まれます。追加されたハンドルがすぐに失敗した場合、running_handleとしてカウントされない可能性があります。

この関数の戻り時にrunning_handlesがゼロ(0)に設定されている場合、進行中の転送はありません。

つまり、libcurlのステータスをポーリングするループを実行し、転送を待機しているデータがある場合は常にcurl_multi_perform()を呼び出し、転送するデータがなくなるまで必要に応じて繰り返します。

ブログ記事 リンク先はこのループについて言及しています:

コードは次のように使用できます

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

//各フレームと呼ばれる更新ループ内
http:Update();

コードでループを実行していないため、コールバックが呼び出されていません。 curl_multi_perform()を1回呼び出しても、新しいデータはまだ受信されていません。

8
Remy Lebeau