解决curl内存泄露的问题
程序员文章站
2022-05-07 15:17:38
...
情景是一个程序一直执行Post,通过http协议上传数据。
一般的办法是:
先curl_easy_init();
之后再curl_easy_perform(curl);
最后 curl_easy_cleanup(curl);
但是这种方法是存在内存泄露的。参见https://*.com/questions/11494950/memory-leak-from-curl-library
示例:
#include <iostream>
#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 <chrono>
#define CURL_STATICLIB //静态链接
#include <curl/curl.h>
#include <qdebug.h>
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<double, std::milli> 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*>((std::string *)lpVoid);
if (NULL == str || NULL == buffer)
{
return -1;
}
char* pData = (char*)buffer;
str->append(pData, size * nmemb);
return nmemb;
}
};
#endif // HTTPCLIENT_HPP
上一篇: php中使用curl 参数详解
下一篇: curl 一下