DLL中DllMain()内独立线程执行libcurl请求时挂起超时无返回
问题分析与解决方案
核心问题排查
- 缺少写入回调函数:仅设置
CURLOPT_WRITEDATA指向std::string,但未指定CURLOPT_WRITEFUNCTION,curl无法识别如何将响应数据写入字符串,会导致数据接收失败甚至触发未定义行为。 - 文件路径转义错误:
fopen("c:\google_logs\dump", "wb")中的反斜杠未转义,需改为"c:\\google_logs\\dump",否则路径解析失败,无法生成verbose日志排查连接细节。 - 提前调用
curl_easy_getinfo:在curl_easy_perform执行前获取响应码,此时请求未发送,得到的response_code必然为0,无实际参考价值。 - DLL环境下curl全局初始化缺失:libcurl需要在DLL加载时调用
curl_global_init完成全局环境初始化,卸载时调用curl_global_cleanup,否则底层环境未就绪会导致请求挂起或失败。 - SSL验证不完整:仅关闭
CURLOPT_SSL_VERIFYPEER不够,需同时设置CURLOPT_SSL_VERIFYHOST为0,避免因主机名验证失败导致连接阻塞。
修正后的代码示例
#pragma once #include <curl/curl.h> #include <spdlog/spdlog.h> #include <string> #include <fstream> #include "json.hpp" // 写入回调函数:将curl响应内容写入std::string size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* s) { size_t newLength = size * nmemb; try { s->append((char*)contents, newLength); } catch(std::bad_alloc&) { return 0; } return newLength; } inline std::string GetData() { CURL* curl = curl_easy_init(); std::ofstream file; file.open("C:/google_logs/test10.txt"); file << "t"; file.close(); if (curl) { std::string all_game_data_url = "https://google.com"; curl_easy_setopt(curl, CURLOPT_URL, all_game_data_url.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L); curl_easy_setopt(curl, CURLOPT_VERBOSE, TRUE); // 修正路径转义,同时判断文件是否成功打开 FILE* filep = fopen("c:\\google_logs\\dump", "wb"); if(filep) { curl_easy_setopt(curl, CURLOPT_STDERR, filep); } std::string response_body; // 绑定写入回调函数与目标字符串 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body); CURLcode response = curl_easy_perform(curl); std::ofstream result_file; result_file.open("C:/google_logs/test19.txt"); result_file << response; result_file.close(); // 请求完成后再获取响应码 long response_code; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); spdlog::error("Response code: {:d}", response_code); if (response != CURLE_OK) { const char* err_msg = curl_easy_strerror(response); spdlog::error("curl_easy_perform() failed: {:s}", err_msg); std::ofstream err_file; err_file.open("C:/google_logs/test14.txt"); err_file << err_msg; err_file.close(); } // 关闭打开的文件指针 if(filep) { fclose(filep); } curl_easy_cleanup(curl); return response_body; } return std::string(); } // DLL入口函数:添加curl全局初始化与清理 BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: curl_global_init(CURL_GLOBAL_ALL); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: curl_global_cleanup(); break; } return TRUE; }
额外注意事项
- 避免在DllMain中启动业务线程:DllMain处于系统加载锁的临界区,线程启动后可能遭遇资源初始化不完整的问题。建议改为提供导出函数,由宿主进程主动调用后再启动线程执行curl请求。
- 目录权限检查:确保程序拥有
C:/google_logs/目录的读写权限,否则日志文件无法创建,难以排查问题。 - libcurl编译配置验证:确认使用的libcurl版本是针对DLL环境编译的,且链接了正确的依赖库(如SSL库),避免因编译配置不匹配导致连接失败。
内容的提问来源于stack exchange,提问作者Ryan Glenn
相关产品推荐
相关产品推荐

