首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ libcurl 網路程式設計完整指南:從入門到實戰

     編輯:關於C++

libcurl 是功能強大的跨平台網路傳輸庫,支援 HTTP/HTTPS、FTP、FTPS 等多種協議。本文系統整理 libcurl 核心 API、常用選項、回調函數設計模式,並提供 5 個實戰範例(GET/POST、網頁抓取、檔案下載、進度條、斷點續傳)。

一、libcurl 基本程式架構

// 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();

二、核心 API 詳解

1. 全域初始化/清理

  • curl_global_init(flags):CURL_GLOBAL_ALL / SSL / WIN32 / NOTHING
  • 執行緒安全警告:curl_global_init/cleanup 非執行緒安全,必須在主執行緒單次呼叫

2. Easy Handle 生命週期

  • curl_easy_init() → 回傳 CURL*
  • curl_easy_cleanup(handle) → 釋放資源
  • 原則:絕不跨執行緒共用 handle

3. 選項設定 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回調 userdataFILE*, string*, 結構體指標
CURLOPT_READFUNCTION資料發送回調size_t fn(ptr, size, nmemb, userdata)
CURLOPT_HEADERFUNCTIONHTTP 標頭接收回調同上簽名
CURLOPT_NOPROGRESS啟用進度回調0 (啟用) / 1 (預設關閉)
CURLOPT_PROGRESSFUNCTION進度回調int fn(userdata, dltotal, dlnow, ultotal, ulnow)
CURLOPT_TIMEOUT總傳輸逾時(秒)30
CURLOPT_CONNECTTIMEOUT連線逾時(秒)10
CURLOPT_FOLLOWLOCATION追蹤重導向1L
CURLOPT_RANGERange 標頭"bytes=0-499"
CURLOPT_RESUME_FROM續傳起始位移1024L

4. 回調函數簽名規範

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);

五、多執行緒與 SSL 注意事項

  • libcurl 本身執行緒安全,但 每個執行緒專用 handle
  • HTTPS 需底層 SSL 庫支援多執行緒:
    • OpenSSL:需設定鎖回調 官方文件
    • GnuTLS / NSS:較友善

六、認證機制

// 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");

七、五大實戰範例

1. 基礎 GET/POST

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;
}

2. 取得 HTML 網頁內容到字串

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;
}

3. 檔案下載儲存(自訂寫入回調)

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);

4. 進度條顯示下載進度

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);

5. 斷點續傳下載

// 關鍵:取得本地檔案大小 → 設定 CURLOPT_RESUME_FROM_LARGE
// 開啟模式 "ab+" 追加寫入
// 回調中解析 Content-Length 取得總大小
// 完整範例見原文程式碼區塊

八、常見坑點速查

  • 32/64 位元不匹配:x64 專案必須連結 x64 版 libcurl
  • CA 憑證驗證失敗:設定 CURLOPT_CAINFO 指定 cacert.pem,或暫時 CURLOPT_SSL_VERIFYPEER, 0L(僅測試用)
  • 中文 URL 編碼:需自行 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
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved