如何在 C++ 中异步执行 curl_multi_perform()?

Posted

技术标签:

【中文标题】如何在 C++ 中异步执行 curl_multi_perform()?【英文标题】:How to do curl_multi_perform() asynchronously in C++? 【发布时间】:2014-08-08 22:10:24 【问题描述】:

我已经开始使用curl 同步进行http 请求。我的问题是如何异步执行?

我做了一些搜索,从这个question 和这个example 中找到了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://***.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://***.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) 提供了一个接口,您可以使用该接口从 libcurl 中提取 fd_set 以在 select() 或 poll() 调用中使用,以便了解何时可能需要注意多堆栈中的传输。这也使您的程序可以很容易地同时等待您自己的私有文件描述符的输入,或者如果您愿意的话,可能时不时地超时。

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

当应用程序发现有可用于 multi_handle 的数据或超时时间已过时,应用程序应调用此函数来读取/写入现在要读取或写入的任何内容等。 curl_multi_perform () 在读/写完成后立即返回。此函数不需要实际有任何数据可供读取或可以写入数据,可以调用它以防万一。它将在第二个参数的整数指针中写入仍在传输数据的句柄数。

如果 running_handles 的数量与上一次调用相比发生了变化(或小于您添加到多句柄的简单句柄数量),则您知道存在一个或多个转移少“跑”。然后,您可以致电curl_multi_info_read(3) 以获取有关每个已完成传输的信息,返回的信息包括 CURLcode 等。如果添加的句柄很快失败,它可能永远不会算作 running_handle。

running_handles 在此函数返回时设置为零 (0),则不再有任何传输正在进行中。

换句话说,您需要运行一个循环来轮询 libcurl 的状态,每当有数据等待传输时调用curl_multi_perform(),并根据需要重复,直到没有任何东西可以传输。

您链接到的blog article 提到了这个循环:

代码可以这样使用

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

// 在某些更新循环中调用每一帧 http:Update();

你没有在你的代码中做任何循环,这就是你的回调没有被调用的原因。当您拨打curl_multi_perform() 一次时,尚未收到新数据。

【讨论】:

curl_multi_perform()的目的是让你在curl忙碌的时候做其他事情,而不必使用线程。如果你使用线程,你也可以使用curl_easy_perform() 来代替。使用curl_multi_perform(),你可以做一些其他的工作,然后轮询 curl 的状态,如果准备好了就调用curl_multi_perform(),然后做一些其他的工作,然后轮询 curl 的状态,等等。在您的示例中,您还没有在循环中做其他工作,这就是您感到困惑的原因。 我现在明白了。因为我想创建一个类来做一些服务器请求,同时让用户做一些其他事情,所以我最好考虑线程。再次感谢您。

以上是关于如何在 C++ 中异步执行 curl_multi_perform()?的主要内容,如果未能解决你的问题,请参考以下文章

PHP 使用 curl_* 系列函数和 curl_multi_* 系列函数进行多接口调用时的性能对比

我可以将 curl_multi/multi_socket 与 libevent 一起使用吗

浅析php curl_multi_*系列函数进行批量http请求

我如何在 C++ 中使用异步函数?

异步比顺序执行花费更长的时间

PHP中curl_multi并发详解