每次运行下面的代码时,我都会立即确定地收到此错误。
我正在尝试使用我使用 nmap 从源代码构建的 libcurl 并使用推荐的过程,有趣的是,我能够使用构建的curl 二进制文件成功发送相同的 GET 请求。我也可以使用 Postman 成功发送此查询。
这是我正在使用的curl命令(我使用
<my.website>
代替实际主机,使用<token>
代替实际正确的令牌):
PS> cd C:\curl-8.8.0\builds\libcurl-vc-x86-release-static-ipv6-sspi-schannel\bin
PS> ./curl --header "Authorization: Bearer <token>" https://<my.website>/api/test
...我得到了预期的结果:
Hello back
但是,当我在 Visual Studio 2022 中的 C++ x86 项目中尝试相同的操作时,如下所示:
#include <curl/curl.h>
#include <iostream>
void test(CURL* curl) {
// setup
const char* url = "https://<my.website>/api/test";
curl_easy_setopt(curl, CURLOPT_URL, url);
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Authorization: Bearer <token>");
setres = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
// request
CURLcode res;
res = curl_easy_perform(curl);
std::cerr << "RESULT: " << res << std::endl;
// request result checking
if (res != CURLE_OK) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
} else {
std::cout << "POST request sent successfully!" << std::endl;
}
// cleanup
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
int main() {
// global initialization
CURL * curl;
curl_global_init(CURL_GLOBAL_SSL);
curl = curl_easy_init();
if (curl) {
test(curl);
} else {
std::cerr << "INIT FAILED" << std::endl;
}
// global cleanup
curl_global_cleanup();
}
...我得到以下输出:
* getaddrinfo() thread failed to start
* Could not resolve host: <my.website>
* Closing connection
RESULT: 6
curl_easy_perform() failed: Couldn't resolve host name
(
这个问题立即出现,等待时间基本为零(根据我找到的一些答案,非零等待时间可能表明 DNS 问题)。
我已经在 Windows 11 上以 x86 模式构建了 libcurl“8.8.0 Schannel WinIDN”(使用 VS 2022 的开发人员命令提示符)。这创建了
C:\curl-8.8.0\builds\libcurl-vc-x86-release-static-ipv6-sspi-schannel\
以及 include
、lib
和 bin
子目录。
我的项目构建为 x86 项目,属性中有以下选项:
C/C++ / General / Additional Include Directories: C:\curl-8.8.0\builds\libcurl-vc-x86-release-static-ipv6-sspi-schannel\include
C/C++ / Preprocessor / Preprocessor Definitions: CURL_STATICLIB;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
Linker / General / Additional Library Directories: C:\curl-8.8.0\builds\libcurl-vc-x86-release-static-ipv6-sspi-schannel\lib
Linker / Input / Additional Dependencies: libcurl_a.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
在试图找出问题所在时,我已阅读这篇文章getaddrinfo线程无法启动#6495,建议还执行以下操作:
curl_version_info_data* ver = curl_version_info(CURLVERSION_NOW);
std::cerr << "VERSION: " << curl_version() << std::endl;
if (!(ver->features & CURL_VERSION_ASYNCHDNS)) {
std::cerr << "SYNCHRONOUS" << std::endl;
} else if (!ver->age || ver->ares_num) {
std::cerr << "ARES" << std::endl;
} else {
std::cerr << "THREADED" << std::endl;
}
...输出:
VERSION: libcurl/8.8.0 Schannel WinIDN
THREADED
这正是我所期望的。
编辑:
在煞费苦心地单步执行 libcurl 调用之后,我发现它最终在这段代码上失败了:
listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listener == CURL_SOCKET_BAD)
return -1;
我无法进入
socket
函数来调试那里发生的事情。
编辑2:
我认为
socket()
方法实际上是一个 Windows 方法,所以我创建了一个单独的项目,其中只添加了这个库:
Linker / Input / Additional Dependencies: Ws2_32.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
...那么即使只是简单的代码:
#include <iostream>
#include <winsock.h>
int main() {
// Create a socket (IPv4, TCP)
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
std::cerr << "Failed to create socket" << std::endl;
return 1;
}
std::cerr << "OK" << std::endl;
}
...结果:
Failed to create socket
有人可以告诉我我做错了什么吗?
解决方案(也如@Botje建议的那样)是在
main()
方法开始时进行适当的初始化:
// Initialize Winsock
WSADATA wsaData;
int iResult;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
这解决了它。