libcurl 是功能強大的跨平台網路傳輸庫,支援 HTTP/HTTPS、FTP、FTPS 等多種協議。本文系統整理 libcurl 核心 API、常用選項、回調函數設計模式,並提供 5 個實戰範例(GET/POST、網頁抓取、檔案下載、進度條、斷點續傳)。
// 1. 全域初始化(進程僅需一次,主執行緒呼叫) curl_global_init(CURL_GLOBAL_ALL); // 2. 建立 easy handle(每個傳輸任務一個) CURL *curl = curl_easy_init(); // 3. 設定傳輸選項(核心步驟) curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); // 4. 執行傳輸 CURLcode res = curl_easy_perform(curl); // 5. 清理 curl_easy_cleanup(curl); curl_global_cleanup();
curl_global_init(flags):CURL_GLOBAL_ALL / SSL / WIN32 / NOTHINGcurl_global_init/cleanup 非執行緒安全,必須在主執行緒單次呼叫curl_easy_init() → 回傳 CURL*curl_easy_cleanup(handle) → 釋放資源curl_easy_setopt參數三態:long、function pointer、object pointer,視選項而定。
| 選項 | 用途 | 典型值 |
|---|---|---|
| CURLOPT_URL | 目標網址 | "https://api.example.com" |
| CURLOPT_WRITEFUNCTION | 資料接收回調 | size_t fn(ptr, size, nmemb, userdata) |
| CURLOPT_WRITEDATA | 回調 userdata | FILE*, string*, 結構體指標 |
| CURLOPT_READFUNCTION | 資料發送回調 | size_t fn(ptr, size, nmemb, userdata) |
| CURLOPT_HEADERFUNCTION | HTTP 標頭接收回調 | 同上簽名 |
| CURLOPT_NOPROGRESS | 啟用進度回調 | 0 (啟用) / 1 (預設關閉) |
| CURLOPT_PROGRESSFUNCTION | 進度回調 | int fn(userdata, dltotal, dlnow, ultotal, ulnow) |
| CURLOPT_TIMEOUT | 總傳輸逾時(秒) | 30 |
| CURLOPT_CONNECTTIMEOUT | 連線逾時(秒) | 10 |
| CURLOPT_FOLLOWLOCATION | 追蹤重導向 | 1L |
| CURLOPT_RANGE | Range 標頭 | "bytes=0-499" |
| CURLOPT_RESUME_FROM | 續傳起始位移 | 1024L |
struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Authorization: Bearer xxx"); headers = curl_slist_append(headers, "Content-Type: application/json"); // 刪除標頭:設定空值 headers = curl_slist_append(headers, "Accept:"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // 使用完畢必須釋放 curl_slist_free_all(headers);
long http_code; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); char *content_type; curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type); struct curl_slist *cookies; curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies);
// Basic / Digest / NTLM / Negotiate 等 curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST | CURLAUTH_BASIC); curl_easy_setopt(curl, CURLOPT_USERPWD, "user:pass"); // Proxy 認證 curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM); curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, "user:pass");
bool http_get(const char *url, const char *outfile) {
CURL *curl = curl_easy_init(); FILE *fp = fopen(outfile, "wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
CURLcode res = curl_easy_perform(curl);
fclose(fp); curl_easy_cleanup(curl);
return res == CURLE_OK;
}
bool http_post(const char *url, const char *postfields, const char *outfile) {
CURL *curl = curl_easy_init(); FILE *fp = fopen(outfile, "wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfields);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
CURLcode res = curl_easy_perform(curl);
fclose(fp); curl_easy_cleanup(curl);
return res == CURLE_OK;
}
struct WriteBuffer { string data; };
size_t write_to_string(void *ptr, size_t size, size_t nmemb, void *userp) {
WriteBuffer *buf = (WriteBuffer*)userp;
buf->data.append((char*)ptr, size * nmemb);
return size * nmemb;
}
string fetch_html(const char *url) {
WriteBuffer buf;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_string);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
return buf.data;
}
size_t write_to_file(void *ptr, size_t size, size_t nmemb, FILE *fp) {
return fwrite(ptr, size, nmemb, fp);
}
// 使用:curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_file);
// curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
int progress_cb(void *clientp, double dltotal, double dlnow,
double ultotal, double ulnow) {
if (dltotal > 0) {
int percent = (int)(dlnow * 100 / dltotal);
printf("\r[%3d%%] %.1f / %.1f MB", percent, dlnow/1e6, dltotal/1e6);
fflush(stdout);
}
return 0;
}
// 啟用:curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
// curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_cb);
// 關鍵:取得本地檔案大小 → 設定 CURLOPT_RESUME_FROM_LARGE // 開啟模式 "ab+" 追加寫入 // 回調中解析 Content-Length 取得總大小 // 完整範例見原文程式碼區塊
CURLOPT_CAINFO 指定 cacert.pem,或暫時 CURLOPT_SSL_VERIFYPEER, 0L(僅測試用)curl_easy_escape 編碼後再傳入CURLOPT_RESUME_FROM_LARGE (curl_off_t) 而非舊版 RESUME_FROM# Linux/macOS gcc main.c -o main -lcurl # Windows (MSVC) cl main.c libcurl.lib # MinGW gcc main.c -o main.exe -lcurl