libcurl/c-ares 中存在 DNS 错误,但命令行 curl 中不存在

libcurl/c-ares 中存在 DNS 错误,但命令行 curl 中不存在

问题描述

我有一个可执行文件,它使用 libcurl 和 libcares 反复将数据发布到 HTTPS 端点。这在某些客户端(不是全部)上偶尔会出现 DNS 解析超时。如果我在命令行 curl 中运行等效命令,则永远不会看到任何超时。

更令人困惑的是,主机在 /etc/hosts 中明确指定,因此不需要任何 DNS 解析。

libcurl(详细模式)的错误是:

* Adding handle: conn: 0xcbca20
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 88 (0xcbca20) send_pipe: 1, recv_pipe: 0
* Resolving timed out after 2002 milliseconds
* Closing connection 88

我的 libcurl 可执行文件每秒发送 2-3 个查询,我大约每 300 个请求就会看到一次此错误。使用命令行 curl,我运行了 10000 个查询,没有一次超时。

有人能建议我尝试解决 libcurl 中的这些错误吗?我需要在 libcurl 设置中添加哪些设置,或者我可能缺少哪些系统配置?

我不确定是否应该将其放在 Stack Overflow、Server Fault 还是 Ask Ubuntu;如果放错了地方,请见谅。

谢谢你的时间!

更多详细信息

客户端是 Ubuntu 12.04,64 位。在多个客户端上都观察到了同样的问题,所有客户端都使用相同的操作系统。

以下代码片段中的用户名/密码/url 已被混淆。

命令行 curl 测试器(使用 v 7.22.0):

while true; do curl -v -u username:password "https://myhost.com/endpoint" -X POST --data "a=x&b=y" >> /tmp/commandLine.log 2>&1; sleep 0.1; done &

Libcurl 源代码(使用 curl 7.30.0,带有 c-ares 1.10.0):

#include <curl/curl.h>
#include <unistd.h>
#include <string>
#include <iostream>

using namespace std;

int main(int argc, char** argv) {

   while (1) {

       // Initialise curl
       CURL *curl = curl_easy_init();

       // Set endpoint
       string urlWithEndpoint = "https://myhost.com/endpoint";
       curl_easy_setopt(curl, CURLOPT_URL, urlWithEndpoint.c_str());

       // Set-up username and password for request
       curl_easy_setopt(curl, CURLOPT_USERPWD, "username:password");

       // Append POST data specific stuff
       string postData = "a=x&b=y";
       long postSize = postData.length();
       curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postSize);
       curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, postData.c_str());

       //set timeouts
       curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
       curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2);
       curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, 60);

       cout << endl << endl << "=========================================================" << endl << endl;
       cout << "Making curl request to " << urlWithEndpoint << "(POST size " << postSize << "B)" << endl;

       // Set curl to log verbose information
       curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);

       // Perform the request
       CURLcode curlRes = curl_easy_perform(curl);

       // Handle response
       bool success = false;
       if (curlRes == CURLE_OK) {
           long httpCode;
           curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
           success = (httpCode==200);
           cout << "Received response " << httpCode << endl;
       } else if ( curlRes == CURLE_OPERATION_TIMEDOUT ) {
           cout << "Received timeout" << endl;
       } else {
           cout << "CURL error" << endl;
       }

       curl_easy_cleanup(curl);

       if (success) {
           cout << "SUCCESS! (" << time(0) << ")" << endl;
           usleep(0.1*1e6);
       } else {
           cout << "FAILURE!!!! (" << time(0) << ")" << endl;
           usleep(10*1e6);
       }

   }

}

答案1

回答我自己的问题...

事实证明,问题出在 lib c-ares 中(它为 libcurl 提供了线程安全的 DNS 解析)。使用 --enable-threaded-resolver 重新编译 libcurl 后,解析超时问题便会消失。

我尝试更新到最新的 c-ares 库,并在 c-ares 论坛上查找类似的错误,但两方面都没有找到。所以我放弃了 c-ares,转而使用 Curl 线程解析器。

相关内容