问题描述
我有一个可执行文件,它使用 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 线程解析器。