我开始使用
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 请求。回调被调用,但仍然需要在执行以下行之前完成。我必须考虑线程吗?
更仔细地再次阅读文档,特别是这些部分:
https://curl.se/libcurl/c/libcurl-multi.html
您的应用程序可以在需要调用 libcurl 来传输数据时从 libcurl 获取知识,这样您就不必疯狂地忙循环并调用 curl_multi_perform(3)。 curl_multi_fdset(3) 提供了一个接口,您可以使用该接口从 libcurl 中提取 fd_sets 以在 select() 或 poll() 调用中使用,以便了解何时需要注意多堆栈中的传输。这也使您的程序很容易同时等待您自己的私有文件描述符上的输入,或者如果您愿意的话,可能会不时超时。
https://curl.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:更新();
您没有在代码中执行任何循环,这就是您的回调未被调用的原因。当您拨打
curl_multi_perform()
一次时,尚未收到新数据。