Libcurl C++例子_C++使用libcurl库的完整示例代码

必须检查 curl_easy_init() 返回值是否为 nullptr,否则未检查时调用 curl_easy_setopt() 会因空指针导致段错误;设置 URL 前须确保以 http:// 或 https:// 开头;HTTPS 需链接 OpenSSL/mbedtls;WRITEFUNCTION 回调签名必须严格匹配;curl_easy_cleanup 必须成对调用且不可重复;多线程需独立句柄。

curl_easy_init 之后必须检查返回值是否为 nullptr

libcurl 的初始化函数 curl_easy_init() 在内存不足或内部初始化失败时会返回 nullptr,但很多示例代码直接假设它一定成功。C++ 程序中若未检查就调用 curl_easy_setopt(),会导致段错误(SIGSEGV)。

  • 永远在 curl_easy_init() 后加 if (!curl) { /* error */ } 判断
  • 常见触发场景:容器环境内存受限、嵌入式设备资源紧张、LD_PRELOAD 干扰
  • 不检查的后果不是报错信息,而是直接 crash,调试时容易误判为网络层问题

设置 CURLOPT_URL 和 CURLOPT_FOLLOWLOCATION 前必须确保 URL 以 http:// 或 https:// 开头

libcurl 对协议前缀敏感,CURLOPT_URL 若传入 "example.com""//cdn.example.com/file" 会被视为非法 URL,curl_easy_perform() 返回 CURLE_URL_MALFORMAT(错误码 3)。

  • 正确写法:curl_easy_setopt(curl, CURLOPT_URL, "https://www./link/4d2fe2e8601f7a8018594d98f28706f2");
  • CURLOPT_FOLLOWLOCATION 默认关闭,重定向(301/302)不会自动跳转;开启后需注意 CURLOPT_MAXREDIRS 防止环形重定向
  • HTTPS 请求必须链接 OpenSSL 或 mbedtls,否则运行时报 CURLE_UNSUPPORTED_PROTOCOL(错误码 1

使用 CURLOPT_WRITEFUNCTION 时,回调函数签名和返回值必须严格匹配

C++ 中若用 lambda 或普通函数做回调,容易因签名不符导致未定义行为——尤其是返回值类型错误时,libcurl 可能截断响应或提前终止传输。

  • 合法签名必须是:size_t function(void *ptr, size_t size, size_t nmemb, void *userdata)
  • 返回值应为实际处理的字节数:return size * nmemb;,不能返回 0(除非主动中止)或大于该值
  • 常见错误:用 intvoid 做返回类型;在类成员函数中忽略 static 修饰(导致隐式 this 参数)
extern "C" size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
  size_t realsize = size * nmemb;
  std::string* mem = static_cast(userp);
  mem->append(static_cast(contents), realsize);
  return realsize;
}

int main() { CURL* curl = curl_easy_init(); if (!curl) return -1;

std::string response; curl_easy_setopt(curl, CURLOPT_URL, "https://www./link/4d2fe2e8601f7a8018594d98f28706f2"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); CURLcode res = curl_easy_perform(curl);

if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } else { printf("Response length: %zu\n", response.length()); }

curl_easy_cleanup(curl); return 0; }

curl_easy_cleanup 必须在每次 curl_easy_init 之后调用,且不能重复调用

libcurl 内部维护连接池、SSL 上下文、DNS 缓存等资源。curl_easy_cleanup() 是唯一释放这些资源的入口。漏掉会导致内存泄漏;重复调用(如异常路径未 guard)会引发 double-free 或崩溃。

  • 推荐用 RAII 封装:构造时 curl_easy_init(),析构时 curl_easy_cleanup()
  • 多线程环境下,每个线程应持有独立 CURL* 句柄,不可共享
  • 若使用 curl_global_init(CURL_GLOBAL_DEFAULT),程序退出前需配对调用 curl_global_cleanup(),否则 Valgrind 会报告全局内存泄漏

libcurl 的坑不在语法复杂,而在“看起来能跑通,但边界条件下悄无声息地失败”。比如 URL 缺协议、回调返回值错一位、cleanup 漏掉一次——这些都不会编译报错,却让程序在特定服务器、特定网络路径或压力测试时突然崩掉。