解决libcurl内存泄露的问题

 

情景是一个程序一直执行Post,通过http协议上传数据。

一般的办法是:

先curl_easy_init();

之后再curl_easy_perform(curl);

最后 curl_easy_cleanup(curl); 

但是这种方法是存在内存泄露的。参见https://stackoverflow.com/questions/11494950/memory-leak-from-curl-library

示例:

#include 
#include "curl/curl.h"
int main(void)
{
    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.del.icio.us/dt");
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
        curl_easy_setopt(curl, CURLOPT_CAINFO, "C:\\Users\\bryan\\GeoTrustGlobalCA.crt");
        /* Perform the request, res will get the return code */ 
        res = curl_easy_perform(curl);
        /* Check for errors */ 
        if(res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));

        /* always cleanup */ 
        curl_easy_cleanup(curl);
    }
    return 0;
}

解决办法是执行curl_global_cleanup()

但是考虑到如果使用http长连接的话,可能会效率更高,因此,在执行上传部分添加了时间判断逻辑,如果超过1分钟就执行curl_global_cleanup(),然后重新新建一个curl对象,否则就使用原来的curl对象。

经过测试,执行curl_global_cleanup()后是没有内存泄露的。

#ifndef HTTPCLIENT_HPP
#define HTTPCLIENT_HPP

#include 

#define CURL_STATICLIB   //静态链接
#include 
#include 

class HttpClient
{

private:  // 不允许复制
     HttpClient( const HttpClient& );
     const HttpClient& operator=( const HttpClient& );

public:
    HttpClient()
    {
        curl_global_init(CURL_GLOBAL_WIN32);
        m_curl = curl_easy_init();//init()
		m_oldTimePoint = std::chrono::system_clock::now();
    }

    ~HttpClient()
    {
        curl_easy_cleanup(m_curl);
        curl_global_cleanup();
    }

    bool send(const std::string &strUrl,std::string &jsonStr)
    {
        string response;
        //string url = "http://127.0.0.1:8080/";


		std::chrono::system_clock::time_point nowTimePoint = std::chrono::system_clock::now();

		std::chrono::duration tm = nowTimePoint - m_oldTimePoint;	// 毫秒
		
		if (tm.count() > 60 * 1000)//如果超过60秒就释放资源,重新生成url对象
		{
			curl_easy_cleanup(m_curl);
			curl_global_cleanup();
			m_curl = curl_easy_init();
			m_oldTimePoint = nowTimePoint;
		}


        int httpCode = httpPost(strUrl, jsonStr, response);
        qDebug() << "retCode:" << httpCode;

        if (httpCode == CURLE_OK)//CURLE_OK=0
            return true;
        else
            return false;
    }

private:

    CURL* m_curl;
	std::chrono::system_clock::time_point m_oldTimePoint;

    int httpPost(const std::string & strUrl, const std::string & strPost, std::string & strResponse)
    {
        CURLcode res;
        CURL* curl = m_curl;// curl_easy_init();
        if (NULL == curl)
        {
            curl = curl_easy_init();
           // return CURLE_FAILED_INIT;
        }

        if ( false )//用于调试的设置
        {
            curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
            curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
        }

        curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
        curl_easy_setopt(curl, CURLOPT_POST, 1);//设置为非0表示本次操作为POST
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 3000);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300);

        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);  //支持服务器跳转
        curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);  // enable TCP keep-alive for this transfer
        curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);	// keep-alive idle time to 120 seconds
        curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);	// interval time between keep-alive probes: 60 seconds

        struct curl_slist* headers = NULL;
        headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        res = curl_easy_perform(curl);

        curl_slist_free_all(headers);//清理headers,防止内存泄漏
        //curl_easy_cleanup(curl);
        return res;
    }

    static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)//curl调试
    {
        if (itype == CURLINFO_TEXT)
        {
            qDebug() << "[TEXT]"<< pData;//logOutput(string(pData));//printf("[TEXT]%s\n", pData);
        }
        else if (itype == CURLINFO_HEADER_IN)
        {
            qDebug() << "[HEADER_IN]" << pData; // printf("[HEADER_IN]%s\n", pData);
        }
        else if (itype == CURLINFO_HEADER_OUT)
        {
            qDebug() << "[HEADER_OUT]" << pData; //printf("[HEADER_OUT]%s\n", pData);
        }
        else if (itype == CURLINFO_DATA_IN)
        {
            qDebug() << "[DATA_IN]" << pData; //printf("[DATA_IN]%s\n", pData);
        }
        else if (itype == CURLINFO_DATA_OUT)
        {
            qDebug() << "[DATA_OUT]" << pData; //printf("[DATA_OUT]%s\n", pData);
        }
        return 0;
    }

    static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
    {
        std::string* str = dynamic_cast((std::string *)lpVoid);
        if (NULL == str || NULL == buffer)
        {
            return -1;
        }

        char* pData = (char*)buffer;
        str->append(pData, size * nmemb);
        return nmemb;
    }

};


#endif // HTTPCLIENT_HPP

 

你可能感兴趣的:(c++)