libcurl下载必须配对使用CURLOPT_WRITEFUNCTION与CURLOPT_WRITEDATA,否则回调接收野指针崩溃;需严格遵循回调签名、返回size*nmemb;Windows中文路径须转宽字符;HTTPS生产环境必须启用SSL证书校验。

用 libcurl 实现下载,别自己手写 HTTP 协议
直接用 libcurl,不是因为“方便”,而是因为手写 HTTP 客户端在 C++ 里几乎必然出错:状态码处理不全、重定向没跟、Content-Length 解析错、chunked 编码没处理、SSL 验证绕过或过度严格……这些细节加起来比业务逻辑还重。libcurl 是经过二十年线上验证的工业级实现,你只需要调它的 C 接口。
常见错误现象:CURLOPT_FOLLOWLOCATION 默认关闭,遇到 302 就停住;CURLOPT_SSL_VERIFYPEER 在某些系统上默认开启但 CA 路径不对,导致 HTTPS 下载失败;没设 CURLOPT_WRITEFUNCTION,数据直接打印到 stdout 或丢弃。
- Linux/macOS 下用包管理器装:
apt install libcurl4-openssl-dev(Ubuntu)或brew install curl(macOS) - Windows 下推荐用 vcpkg:
vcpkg install curl:x64-windows - 编译时链接:
-lcurl(GCC/Clang)或链接libcurl.lib(MSVC)
核心代码就三段:初始化、设置选项、执行
重点不是“怎么写”,而是“哪些选项不能漏”。下面是最小可运行片段,去掉注释就是 15 行左右:
#include <curl/curl.h>
#include <fstream>
<p>size_t write_callback(void<em> ptr, size_t size, size_t nmemb, void</em> userdata) {
std::ofstream<em> file = static_cast<std::ofstream</em>>(userdata);
size_t real_size = size <em> nmemb;
file->write(static_cast<char</em>>(ptr), real_size);
return real_size;
}</p><p>int download_file(const char<em> url, const char</em> path) {
CURL* curl = curl_easy_init();
if (!curl) return -1;</p><pre class="brush:php;toolbar:false;">std::ofstream file(path, std::ios::binary);
if (!file.is_open()) return -2;
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &file);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // 必开
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 测试可关,生产需配 CA
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // 同上
CURLcode res = curl_easy_perform(curl);
file.close();
curl_easy_cleanup(curl);
return (res == CURLE_OK) ? 0 : -3;}
注意:CURLOPT_SSL_VERIFYPEER 和 CURLOPT_SSL_VERIFYHOST 在开发阶段设为 0L 可跳过证书校验,但上线前必须改回 1L 并通过 CURLOPT_CAINFO 指定 PEM 文件路径,否则中间人攻击风险真实存在。
立即学习“C++免费学习笔记(深入)”;
大文件下载要加进度回调和超时控制
没进度回调,用户不知道卡在哪;没超时,DNS 挂了或服务器失联会卡死整个程序。libcurl 提供 CURLOPT_XFERINFOFUNCTION 和 CURLOPT_TIMEOUT,但要注意:旧版本(CURLOPT_PROGRESSFUNCTION,行为也略有不同。
-
CURLOPT_TIMEOUT控制总耗时(单位秒),建议设为 30–120,视文件大小而定 -
CURLOPT_CONNECTTIMEOUT单独设连接超时(如 10 秒),避免 DNS 延迟拖累整体 - 进度回调函数返回
CURLE_OK继续,返回非零值中止下载 - 不要在回调里做耗时操作(比如弹窗、日志写磁盘),否则拖慢下载速度
Windows 下容易忽略的初始化和字符编码
Windows 上不调 curl_global_init(CURL_GLOBAL_DEFAULT),首次调用 curl_easy_init() 可能失败且无明确报错;另外,传入的 URL 如果含中文路径或参数,必须是 UTF-8 编码——Windows 控制台默认是 GBK,直接传 argv[1] 很可能 404。
常见错误现象:curl_easy_perform 返回 CURLE_URL_MALFORMAT,但 URL 看起来完全合法;或者下载成功但文件名乱码、保存路径错位。
- 全局初始化放在 main 开头:
curl_global_init(CURL_GLOBAL_DEFAULT),退出前调curl_global_cleanup() - URL 中文部分用
curl_easy_escape编码,例如:curl_easy_escape(curl, "北京", 6) - 避免直接用
std::cout 打印错误——它返回的是 ASCII 字符串,Windows 控制台可能显示为方块
真正麻烦的从来不是“怎么下”,而是“下到一半断了怎么办”“服务器返回 206 怎么续传”“如何校验下载完整性”。这些得靠 CURLOPT_RANGE、CURLOPT_HEADERFUNCTION 和外部哈希库配合,不是加两行代码就能搞定的。


















