如何在 C++ 中异步执行 curl_multi_perform()?
我开始使用 curl
同步处理 http 请求.我的问题是如何异步执行此操作?
我做了一些搜索,从这个curl_multi_*接口的文档-synchronous-or-asynchronous">问题 和这个 示例 但它根本没有解决任何问题.
我的简化代码:
CURLM *curlm;int handle_count = 0;curlm = curl_multi_init();卷曲 *卷曲 = NULL;curl = curl_easy_init();如果(卷曲){curl_easy_setopt(curl, CURLOPT_URL, "https://stackoverflow.com/");curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);curl_multi_add_handle(卷曲,卷曲);curl_multi_perform(卷曲,&handle_count);}curl_global_cleanup();
回调方法 writeCallback
没有被调用,什么也没有发生.
请多多指教.
根据@Remy 的以下回答,我得到了这个,但似乎并不是我真正需要的.因为使用循环仍然是一个阻塞循环.如果我做错或误解了什么,请告诉我.实际上,我对 C++ 还很陌生.
这是我的代码:
int main(int argc, const char * argv[]){使用命名空间标准;卷曲 *卷曲;int handle_count;curlm = curl_multi_init();卷曲 *curl1 = NULL;curl1 = curl_easy_init();卷曲 *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(卷曲,curl1);curl_easy_setopt(curl2, CURLOPT_URL, "http://google.com/");curl_easy_setopt(curl2, CURLOPT_WRITEFUNCTION, writeCallback);curl_multi_add_handle(卷曲,curl2);CURLMcode 代码;同时(1){代码 = curl_multi_perform(curlm, &handle_count);如果(句柄计数== 0){休息;}}}curl_global_cleanup();cout<<"你好,世界!
";返回0;}
我现在可以同时执行 2 个 http 请求.回调被调用但仍需要在执行以下行之前完成.我需要考虑线程吗?
解决方案再次仔细阅读文档,尤其是以下部分:
http://curl.haxx.se/libcurl/c/libcurl-multi.html一个>
<块引用>你的应用程序可以从 libcurl 获取知识,当它想要被调用来传输数据时,这样你就不必忙循环并调用它 curl_multi_perform(3) 像疯了一样.curl_multi_fdset(3) 提供了一个界面,您可以使用它从 libcurl 中提取 fd_sets 以在选择中使用() 或 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()
,根据需要重复,直到没有任何数据可以传输.
您链接到的博客文章提到了这种循环:
<块引用>代码可以这样使用
http http;
http:AddRequest("http://www.google.com");
//在一些称为每一帧的更新循环中
http:Update();
您没有在代码中进行任何循环,这就是没有调用回调的原因.当您调用 curl_multi_perform()
一次时,尚未收到新数据.
I have come to use curl
synchronously doing a http request. My question is how can I do it asynchronously?
I did some searches which lead me to the documentation of curl_multi_*
interface from this question and this example but it didn't solve anything at all.
My simplified code:
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();
The callback method writeCallback
doesn't get called and nothing happens.
Please advise me.
EDIT:
According to @Remy's below answer, I got this but seems that it's not quite what I really needed. Cause using a loop is still a blocking one. Please tell me if I'm doing wrong or misunderstanding something. I'm actually pretty new to C++.
Here's my code again:
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!
";
return 0;
}
I can now do 2 http requests simultaneously. Callbacks are called but still need to finish before executing following lines. Will I have to think of thread?
解决方案Read the documentation again more carefully, particularly these portions:
http://curl.haxx.se/libcurl/c/libcurl-multi.html
Your application can acquire knowledge from libcurl when it would like to get invoked to transfer data, so that you don't have to busy-loop and call that curl_multi_perform(3) like crazy. curl_multi_fdset(3) offers an interface using which you can extract fd_sets from libcurl to use in select() or poll() calls in order to get to know when the transfers in the multi stack might need attention. This also makes it very easy for your program to wait for input on your own private file descriptors at the same time or perhaps timeout every now and then, should you want that.
http://curl.haxx.se/libcurl/c/curl_multi_perform.html
When an application has found out there's data available for the multi_handle or a timeout has elapsed, the application should call this function to read/write whatever there is to read or write right now etc. curl_multi_perform() returns as soon as the reads/writes are done. This function does not require that there actually is any data available for reading or that data can be written, it can be called just in case. It will write the number of handles that still transfer data in the second argument's integer-pointer.
If the amount of running_handles is changed from the previous call (or is less than the amount of easy handles you've added to the multi handle), you know that there is one or more transfers less "running". You can then call curl_multi_info_read(3) to get information about each individual completed transfer, and that returned info includes CURLcode and more. If an added handle fails very quickly, it may never be counted as a running_handle.
When running_handles is set to zero (0) on the return of this function, there is no longer any transfers in progress.
In other words, you need to run a loop that polls libcurl for its status, calling curl_multi_perform()
whenever there is data waiting to be transferred, repeating as needed until there is nothing left to transfer.
The blog article you linked to mentions this looping:
The code can be used like
Http http;
http:AddRequest("http://www.google.com");// In some update loop called each frame
http:Update();
You are not doing any looping in your code, that is why your callback is not being called. New data has not been received yet when you call curl_multi_perform()
one time.
相关文章