You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 08:20:27