6.3. libcurl
libcurl 是功能强大的传输库,支持多种协议(HTTP, HTTPS, FTP 等)。
6.3.1. 安装
# Ubuntu
sudo apt install libcurl4-openssl-dev
# macOS
brew install curl
# 编译
g++ -lcurl program.cpp
6.3.2. HTTP GET
#include <curl/curl.h>
#include <string>
size_t write_callback(char* ptr, size_t size, size_t nmemb,
std::string* data) {
data->append(ptr, size * nmemb);
return size * nmemb;
}
std::string http_get(const std::string& url) {
CURL* curl = curl_easy_init();
std::string response;
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
std::cerr << "curl error: " << curl_easy_strerror(res) << "\n";
}
curl_easy_cleanup(curl);
}
return response;
}
6.3.3. HTTP POST
std::string http_post(const std::string& url,
const std::string& data,
const std::string& content_type = "application/json") {
CURL* curl = curl_easy_init();
std::string response;
if (curl) {
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers,
("Content-Type: " + content_type).c_str());
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
CURLcode res = curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
return response;
}
6.3.4. 文件下载
size_t file_write_callback(char* ptr, size_t size, size_t nmemb,
FILE* file) {
return fwrite(ptr, size, nmemb, file);
}
bool download_file(const std::string& url, const std::string& filename) {
CURL* curl = curl_easy_init();
FILE* file = fopen(filename.c_str(), "wb");
if (curl && file) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, file_write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
// 显示进度
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
CURLcode res = curl_easy_perform(curl);
fclose(file);
curl_easy_cleanup(curl);
return res == CURLE_OK;
}
return false;
}
6.3.5. 文件上传
bool upload_file(const std::string& url, const std::string& filename) {
CURL* curl = curl_easy_init();
if (curl) {
curl_mime* form = curl_mime_init(curl);
curl_mimepart* field = curl_mime_addpart(form);
curl_mime_name(field, "file");
curl_mime_filedata(field, filename.c_str());
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
CURLcode res = curl_easy_perform(curl);
curl_mime_free(form);
curl_easy_cleanup(curl);
return res == CURLE_OK;
}
return false;
}
6.3.6. HTTPS 与证书
void https_request(const std::string& url) {
CURL* curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
// SSL 选项
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
// 指定 CA 证书
curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/ca-bundle.crt");
// 客户端证书
curl_easy_setopt(curl, CURLOPT_SSLCERT, "/path/to/client.crt");
curl_easy_setopt(curl, CURLOPT_SSLKEY, "/path/to/client.key");
curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
}
6.3.7. RAII 封装
class Curl {
CURL* handle_;
struct curl_slist* headers_ = nullptr;
std::string response_;
public:
Curl() : handle_(curl_easy_init()) {
if (!handle_) throw std::runtime_error("curl_easy_init failed");
curl_easy_setopt(handle_, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(handle_, CURLOPT_WRITEDATA, &response_);
}
~Curl() {
if (headers_) curl_slist_free_all(headers_);
curl_easy_cleanup(handle_);
}
Curl& url(const std::string& url) {
curl_easy_setopt(handle_, CURLOPT_URL, url.c_str());
return *this;
}
Curl& header(const std::string& header) {
headers_ = curl_slist_append(headers_, header.c_str());
curl_easy_setopt(handle_, CURLOPT_HTTPHEADER, headers_);
return *this;
}
Curl& post(const std::string& data) {
curl_easy_setopt(handle_, CURLOPT_POSTFIELDS, data.c_str());
return *this;
}
Curl& timeout(long seconds) {
curl_easy_setopt(handle_, CURLOPT_TIMEOUT, seconds);
return *this;
}
std::string perform() {
response_.clear();
CURLcode res = curl_easy_perform(handle_);
if (res != CURLE_OK) {
throw std::runtime_error(curl_easy_strerror(res));
}
return response_;
}
long status_code() const {
long code;
curl_easy_getinfo(handle_, CURLINFO_RESPONSE_CODE, &code);
return code;
}
private:
static size_t write_callback(char* ptr, size_t size, size_t nmemb,
std::string* data) {
data->append(ptr, size * nmemb);
return size * nmemb;
}
};
// 使用
auto response = Curl()
.url("https://api.example.com/data")
.header("Content-Type: application/json")
.header("Authorization: Bearer token")
.post(R"({"key": "value"})")
.timeout(30)
.perform();
小技巧
libcurl 使用要点:
调用
curl_global_init()初始化(程序启动时一次)使用 RAII 确保资源释放
检查所有返回值
生产环境验证 SSL 证书
考虑使用连接池提高性能