如何正确使用带有 libcurl C++ 库的 Keep-Alive 标头

How to correctly use Keep-Alive header with libcurl C++ library

提问人:chargedfever 提问时间:2/20/2023 最后编辑:273Kchargedfever 更新时间:2/21/2023 访问量:142

问:

我有一个应用程序,它对后端服务器进行了数百万次调用,以从数据库中获取一些数据。它使用带有 TCP 的 HTTP API,执行请求的平均时间为 150-200 毫秒。在后端服务器上花费的时间仅为 1-2 毫秒。花费大量时间进行DNS查找和三向SSL握手。 我想利用TCP功能不关闭与后端的TCP连接。 我注意到,仅仅添加请求的标头就减少了执行请求所需的时间。这是通过 POSTMAN 注意到的。Keep-Alive

但是,通过我们的 C++ 应用程序执行时,我看不到类似的数据。

下面是我们使用的代码。

INT CCurlHTTP::HTTPSPost(const CString& endPointUrl, const CString& urlparam,const CString& cookie){
    
    CURL *curl;
    CURLcode res;
    struct curl_slist *headers=NULL;
    char errbuf[CURL_ERROR_SIZE];

    curl = curl_easy_init();

    CString KeepAlive = "Connection: keep-alive";
    CString KeepAliveSettings = "Keep-Alive: timeout=100, max=100";

    get_request req;
    req.buffer =0;
    req.len =0;
    req.buflen =0;

    if(curl) 
    {
        //add url, headers, and paramaters to the request
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
        curl_easy_setopt(curl, CURLOPT_URL, endPointUrl);
        curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
        headers = curl_slist_append(headers, m_httpHeadAccept);
        headers = curl_slist_append(headers, m_httpContentType);
        headers = curl_slist_append(headers, KeepAlive);
        headers = curl_slist_append(headers, KeepAliveSettings);
        //callback function used to save response
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_String);
        curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
        curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 5L);
        req.buffer = (unsigned char*) malloc(CHUNK_SIZE);
        req.buflen = CHUNK_SIZE;
        req.len = 0;
        curl_easy_setopt(curl,CURLOPT_WRITEDATA, (void *)&req);
        
        if (!cookie.IsEmpty())
        {
            headers = curl_slist_append(headers, m_DBAuthCertficate); //What is difference between this and line no 118?
            CString pCookie = "DBAuthTicket=" + cookie;
            curl_easy_setopt(curl,CURLOPT_COOKIE, pCookie);
        }
        else
        {
            headers = curl_slist_append(headers, m_OAuthToken);
        }
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, urlparam);
        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
        errbuf[0] = 0;
        
        curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 512000);
        CFileTime start, end;
                CFileTimeSpan duration;

        start = CFileTime::GetCurrentTime();

        res = curl_easy_perform(curl);

        end = CFileTime::GetCurrentTime();
        duration = (end - start);

        CString elapsed, logMsg;
        elapsed.Format("%ld",duration.GetTimeSpan()/10000);
        logMsg.Format("[CCurlHTTP::HTTPSPost::%d]Respone time = %s ms",__LINE__, elapsed);
        UTHelper::Get().WriteLog(logMsg);

        long res_code;
        
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_code);

        if(res_code != 200 && res_code != 201)
        {
            res = CURLE_HTTP_RETURNED_ERROR;
        }

        m_response = (char*)req.buffer;
        m_errDescription.Format("%ld", res_code);
        len = req.len;
        buflen = req.buflen;

        //curl_easy_cleanup(curl);
        free(req.buffer);
    }
    return res;
}

这段代码由单线程应用程序以及多线程 Web 应用程序(VBScript + C++ COM DLL)使用,它是一个非常传统的代码库。

问题

  1. 每次我们想要执行新请求时,我们都会创建一个新的 CurlHTTP 类。curl_easy_init每次都会给我们新的卷曲手柄,还是会发出相同的卷曲手柄。
  2. 如何使它与标题一起工作。相同的代码对这些标头完全没有影响。响应时间仍为 150-200 毫秒。Keep-Alive
  3. 请尽一切可能提供帮助。我无法制作 CurlHTTP 单例,因为此代码也用于多线程环境,如果我尝试同步,可能会导致瓶颈。
  4. 我应该在哪里初始化curl_global_init以及我应该在那里传递哪些参数。

遗留代码 - C++ 98 + VC7。

visual-c++ libcurl c++98

评论

0赞 Igor Tandetnik 2/20/2023
默认情况下,libcurl 会自动重用连接 - 如果您继续使用相同的句柄。所示代码为每个请求创建一个新句柄(此外,还会泄漏它),因此库必须从头开始协商新的连接。当然,每次调用它时都会分配一个新句柄 - 据它所知,您希望并行发出多个请求。它不能知道你只是泄露了以前的句柄,并且不打算再使用它了。CURLcurl_easy_init
0赞 Igor Tandetnik 2/20/2023
再:。顾名思义,此调用的合理位置是 in(或应用程序的任何入口点),合理的参数是 。curl_global_initmainCURL_GLOBAL_DEFAULT
0赞 chargedfever 2/21/2023
如何重复使用相同的卷曲手柄?我应该将 clasd 声明为 Singleton 吗?如果我这样做,它肯定会影响何时将此代码放入多线程环境中。请在这里指导我
0赞 Igor Tandetnik 2/21/2023
我对你的设计了解不够,无法推荐你应该如何管理你的连接。您不能同时通过同一连接发送多个请求,因此,无论如何,您需要决定何时可以重用连接以及何时需要创建新连接。一旦你阐明了这些条件,就很清楚如何管理句柄以满足它们。CURL

答: 暂无答案