libcurl 是一個功能強大的跨平臺網絡傳輸庫,支持多種協議。

關注“碼農愛學習”,設置“星標公眾號”

本篇來介紹libcul的C語言編程,實現一個文件下載的功能。
CURL是libcurl 的核心句柄,每個請求對應一個 CURL 實例,是配置請求參數、執行操作的主要載體。
其特性包括:
CURLcode是函數返回值類型,用于判斷操作是否成功。
成功狀態為:CURLE_OK
所有的返回值枚舉如下:
typedef enum {
CURLE_OK = 0, /* 操作成功 */
CURLE_UNSUPPORTED_PROTOCOL, /* 不支持的協議 */
CURLE_FAILED_INIT, /* 初始化失敗(如 curl_global_init 調用失敗) */
CURLE_URL_MALFORMAT, /* URL 格式錯誤 */
CURLE_URL_MALFORMAT_USER, /* URL 中的用戶名/密碼格式錯誤 */
CURLE_COULDNT_RESOLVE_PROXY, /* 無法解析代理服務器 */
CURLE_COULDNT_RESOLVE_HOST, /* 無法解析主機名(DNS 失敗) */
CURLE_COULDNT_CONNECT, /* 無法連接到服務器 */
CURLE_WEIRD_SERVER_REPLY, /* 服務器返回異常響應 */
CURLE_REMOTE_ACCESS_DENIED, /* 遠程訪問被拒絕(如權限不足) */
CURLE_FTP_ACCEPT_FAILED, /* FTP 接受連接失敗 */
CURLE_FTP_WEIRD_PASS_REPLY, /* FTP 密碼響應異常 */
CURLE_FTP_ACCEPT_TIMEOUT, /* FTP 接受超時 */
CURLE_FTP_WEIRD_PASV_REPLY, /* FTP PASV 命令響應異常 */
CURLE_FTP_WEIRD_227_FORMAT, /* FTP 227 響應格式錯誤 */
CURLE_FTP_CANT_GET_HOST, /* FTP 無法獲取主機信息 */
CURLE_HTTP2, /* HTTP/2 相關錯誤 */
CURLE_FTP_COULDNT_SET_TYPE, /* FTP 無法設置傳輸類型(ASCII/BINARY) */
CURLE_PARTIAL_FILE, /* 只接收到部分文件(未完成全量下載) */
CURLE_FTP_COULDNT_RETR_FILE, /* FTP 無法檢索文件 */
CURLE_OBSOLETE4, /* 已廢棄(歷史版本使用) */
CURLE_QUOTE_ERROR, /* FTP QUOTE 命令執行失敗 */
CURLE_HTTP_RETURNED_ERROR, /* HTTP 服務器返回錯誤狀態碼(如 4xx、5xx) */
CURLE_WRITE_ERROR, /* 寫入數據失敗(如本地文件寫入失敗) */
CURLE_OBSOLETE9, /* 已廢棄 */
CURLE_UPLOAD_FAILED, /* 上傳失敗 */
CURLE_READ_ERROR, /* 讀取數據失敗(如本地文件讀取失敗) */
CURLE_OUT_OF_MEMORY, /* 內存不足 */
CURLE_OPERATION_TIMEDOUT, /* 操作超時 */
CURLE_OBSOLETE14, /* 已廢棄 */
CURLE_FTP_PORT_FAILED, /* FTP PORT 命令執行失敗 */
CURLE_FTP_COULDNT_USE_REST, /* FTP REST 命令不被支持 */
CURLE_OBSOLETE17, /* 已廢棄 */
CURLE_RANGE_ERROR, /* 范圍請求錯誤(服務器不支持 Range 或范圍無效) */
CURLE_HTTP_POST_ERROR, /* HTTP POST 數據傳輸錯誤 */
CURLE_SSL_CONNECT_ERROR, /* SSL/TLS 連接失敗 */
CURLE_BAD_DOWNLOAD_RESUME, /* 斷點續傳失敗(如文件不存在或偏移量無效) */
CURLE_FILE_COULDNT_READ_FILE, /* 無法讀取本地文件 */
CURLE_LDAP_CANNOT_BIND, /* LDAP 綁定失敗 */
CURLE_LDAP_SEARCH_FAILED, /* LDAP 搜索失敗 */
CURLE_OBSOLETE24, /* 已廢棄 */
CURLE_FUNCTION_NOT_FOUND, /* 未找到指定的回調函數 */
CURLE_ABORTED_BY_CALLBACK, /* 被回調函數中止(如進度回調返回非零值) */
CURLE_BAD_FUNCTION_ARGUMENT, /* 回調函數參數錯誤 */
CURLE_OBSOLETE28, /* 已廢棄 */
CURLE_OBSOLETE29, /* 已廢棄 */
CURLE_PARTIAL_FILE_FROM_cache, /* 從緩存獲取到部分文件 */
CURLE_OBSOLETE31, /* 已廢棄 */
CURLE_SSL_ENGINE_NOTFOUND, /* 未找到 SSL 引擎 */
CURLE_SSL_ENGINE_SETFAILED, /* SSL 引擎初始化失敗 */
CURLE_SEND_ERROR, /* 發送數據失敗(網絡發送錯誤) */
CURLE_RECV_ERROR, /* 接收數據失敗(網絡接收錯誤) */
CURLE_OBSOLETE36, /* 已廢棄 */
CURLE_SSL_CERTPROBLEM, /* SSL 證書問題(如無效、過期) */
CURLE_SSL_CIPHER, /* 無法協商 SSL 加密套件 */
CURLE_SSL_CACERT, /* 無法驗證 SSL CA 證書 */
CURLE_BAD_CONTENT_ENCODING, /* 內容編碼錯誤(如服務器返回無效的 gzip 數據) */
CURLE_LDAP_INVALID_URL, /* LDAP URL 無效 */
CURLE_FILESIZE_EXCEEDED, /* 文件大小超出限制 */
CURLE_USE_SSL_FAILED, /* 啟用 SSL 失敗 */
CURLE_SEND_FAIL_REWIND, /* 發送數據前重繞(rewind)失敗 */
CURLE_SSL_ENGINE_INITFAILED, /* SSL 引擎初始化失敗 */
CURLE_LOGIN_DENIED, /* 登錄被拒絕(如用戶名/密碼錯誤) */
CURLE_TFTP_NOTFOUND, /* TFTP 文件未找到 */
CURLE_TFTP_PERM, /* TFTP 權限錯誤 */
CURLE_REMOTE_DISK_FULL, /* 遠程磁盤滿 */
CURLE_TFTP_ILLEGAL, /* TFTP 非法操作 */
CURLE_TFTP_UNKNOWNID, /* TFTP 未知傳輸 ID */
CURLE_REMOTE_FILE_EXISTS, /* 遠程文件已存在(不允許覆蓋) */
CURLE_TFTP_NOSUCHUSER, /* TFTP 無此用戶 */
CURLE_CONV_FAILED, /* 字符編碼轉換失敗 */
CURLE_CONV_REQD, /* 需要字符編碼轉換但未啟用 */
CURLE_SSL_CACERT_BADFILE, /* SSL CA 證書文件不存在或無法讀取 */
CURLE_REMOTE_FILE_NOT_FOUND, /* 遠程文件未找到 */
CURLE_SSH, /* SSH 相關錯誤 */
CURLE_SSL_SHUTDOWN_FAILED, /* SSL 關閉失敗 */
CURLE_AGAIN, /* 操作需要重試(非錯誤,用于異步操作) */
CURLE_SSL_CRL_BADFILE, /* CRL 文件錯誤 */
CURLE_SSL_ISSUER_ERROR, /* SSL issuer 證書驗證失敗 */
CURLE_FTP_PRET_FAILED, /* FTP PRET 命令失敗 */
CURLE_RTSP_CSEQ_ERROR, /* RTSP CSEQ 不匹配 */
CURLE_RTSP_SESSION_ERROR, /* RTSP 會話錯誤 */
CURLE_FTP_BAD_FILE_LIST, /* FTP 文件列表格式錯誤 */
CURLE_CHUNK_FAILED, /* HTTP 分塊傳輸編碼錯誤 */
CURLE_NO_CONNECTION_AVAILABLE, /* 無可用連接(連接池耗盡) */
CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* SSL 固定公鑰不匹配 */
CURLE_SSL_INVALIDCERTSTATUS, /* SSL 證書狀態無效 */
CURLE_HTTP2_STREAM, /* HTTP/2 流錯誤 */
CURLE_RECURSIVE_API_CALL, /* 遞歸調用 libcurl API */
CURLE_AUTH_ERROR, /* 認證錯誤 */
CURLE_HTTP3, /* HTTP/3 相關錯誤 */
CURLE_QUIC_CONNECT_ERROR, /* QUIC 連接錯誤 */
CURLE_PROXY, /* 代理相關錯誤 */
CURLE_SSL_CLIENTCERT, /* 客戶端證書錯誤 */
CURLE_UNRECOVERABLE_POLL, /* 無法恢復的輪詢錯誤 */
CURLE_LAST /* 標記枚舉結束(無實際意義) */
} CURLcode;
初始化 libcurl 全局環境,必須在所有其他 libcurl 函數之前調用
CURLcode curl_global_init(long flags);
flags 通常使用 CURL_GLOBAL_DEFAULT(默認初始化)CURLcode 類型,成功返回 CURLE_OKcurl_global_init 通常需要手動調用,如果不調用,在第一次調用curl_easy_init時,libcurl 會隱式調用
curl_global_init(CURL_GLOBAL_DEFAULT),但這種行為不可靠,可能存在以下問題:
curl_global_init 的返回值(若初始化失敗,難以排查原因)如果代碼邏輯較簡單,或剛開始學習curl,簡化邏輯可先只調用curl_easy_init。
創建一個 CURL 句柄,用于配置單次請求
CURL *curl_easy_init(void);
CURL* 句柄,失敗返回 NULL釋放 CURL 句柄資源
void curl_easy_cleanup(CURL *curl);
清理 libcurl 全局環境,程序結束前調用
void curl_global_cleanup(void);
設置 CURL 句柄的各種選項(核心函數,幾乎所有配置都通過它完成)
函數原型:
CURLcode curl_easy_setopt(CURL *curl, CURLoption option, parameter);
參數:
CURL *curl:指向 CURL 句柄的指針,由 curl_easy_init() 創建,用于標識一個 curl 會話
CURLoption option:枚舉類型的選項參數,指定要設置的具體配置(如 URL、超時時間、回調函數等),例如:
CURLOPT_URL(設置請求的 URL)CURLOPT_WRITEFUNCTION(設置數據接收回調函數)parameter:選項對應的參數值,類型根據option不同而變化:
0 或 NULL(根據具體選項要求)CURLOPT_URL:設置下載的 URL(必填)
示例:curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/file.zip");
CURLOPT_WRITEFUNCTION:設置回調函數,用于處理下載的文件數據
回調函數原型:
size_t (*curl_write_callback)(void *ptr, size_t size, size_t nmemb, void *userp);
ptr:下載到的數據緩沖區;size:每個數據塊的大小;nmemb:數據塊數量;userp:自定義參數(通常是文件指針等);size * nmemb,否則可能中斷下載)。CURLOPT_WRITEDATA:設置傳遞給 CURLOPT_WRITEFUNCTION 回調的自定義參數(如文件指針)
示例:curl_easy_setopt(curl, CURLOPT_WRITEDATA, file_ptr);
CURLOPT_FOLLOWLOCATION:設置為 1L 時,自動跟隨 HTTP 重定向(如 301/302)
CURLOPT_SSL_VERIFYPEER:設置為 0L 時,忽略 SSL 證書驗證(僅測試用,生產環境不推薦)
CURLOPT_PROGRESSFUNCTION:設置進度回調函數,用于跟蹤下載進度。
回調原型:
int (*progress_callback)(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
dltotal:總下載大小dlnow:已下載大小CURLOPT_NOPROGRESS:設置為 0L 時,啟用進度回調(需配合 CURLOPT_PROGRESSFUNCTION 使用)
執行配置好的請求(開始數據傳輸)
CURLcode curl_easy_perform(CURL *curl);
CURLcode 類型,CURLE_OK 表示下載成功獲取下載相關信息(需在 curl_easy_perform 執行后調用)
CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
參數:
CURL *curl:指向已執行過請求的 CURL 句柄的指針CURLINFO info:枚舉類型的參數,指定要獲取的信息類型,例如:CURLINFO_RESPONSE_CODE(HTTP 響應碼)CURLINFO_SIZE_DOWNLOAD(下載總字節數)...:可變參數,指向用于存儲結果的變量指針,類型根據 info 不同而變化(如整數指針、雙精度指針、字符串指針等)主要調用的接口如下:
void http_file_download(const char *url, const char *name)
{
printf("[%s] in\n", __func__);
int fd = open(name, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
if (-1 == fd)
{
printf("[%s] create file:%s failed\n", __func__, name);
return;
}
printf("[%s] create file:%s ok\n", __func__, name);
printf("[%s] curl init\n", __func__);
CURL *curl = curl_easy_init();
printf("[%s] curl setopt, url:%s\n", __func__, url);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fd);
printf("[%s] curl performt\n", __func__);
curl_easy_perform(curl);
printf("[%s] close file\n", __func__);
close(fd);
printf("[%s] out\n", __func__);
}
下載數據的回調,需要根據回調函數的原型,自己實現具體的內容,這里就是將接收的數據通過write方法寫入自己創建的文件。
文件的創建是在上面的http_file_download中通過open方法創建一個文件,并通過curl_easy_setopt的CURLOPT_WRITEDATA選項將文件
的fd句柄傳給回調函數。
size_t write_file_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
{
static int i = 0;
size_t this_size = size * nmemb;
printf("[%s] <%d> total size:%zu\n", __func__, ++i, this_size);
int fd = *((int *)userdata);
write(fd, ptr, this_size);
return this_size;
}
要測試文件下載,需要先找一個文件下載連接,可以先通過瀏覽器下載一個文件,然后在下載記錄中,復制其下載鏈接:

文件下載的測試主函數中,就是調用上面的curl函數接口,傳入下載鏈接:
// gcc download_file.c -o download_file -l curl
#include <stdio.h>
#include <curl/curl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
constchar *file_url = "https://vscode.download.prss.microsoft.com/dbazure/download/stable/488a1f239235055e34e673291fb8d8c810886f81/code_1.102.3-1753759567_amd64.deb";
constchar *file_name = "my_download.deb";
int main()
{
printf("hello\n");
time_t start;
time_t end;
time(&start);
http_file_download(file_url, file_name);
time(&end);
int esapsed = difftime(end, start);
printf("esapsed time:%d sec\n", esapsed);
return0;
}
運行結果下:

通過linux系統自帶的md5sum功能,對比通過瀏覽器下載的文件,和通過curl編寫的程序下載的文件,MD5的值是一樣的,說明下載的文件是對的。
curl下載文件,主要時間是在執行curl_easy_perform時阻塞,直到文件下載完成。
使用多線程下載的基本思路,就是創建多個curl句柄,對要下載的文件進行分段下載,在多個線程中,各自執行curl_easy_perform,來下載文件的各個部分的數據。
在下載主邏輯中,使用多線程的下載,與剛才單線程的主要區別是:
void http_file_download(const char *url, const char *name)
{
printf("[%s] in\n", __func__);
//要下載的文件長度
longlong file_length = get_download_length(url);
if (-1 == file_length)
{
return;
}
printf("[%s] file_length:%lld\n", __func__, file_length);
//創建一個文件
int fd = open(name, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
if (-1 == fd)
{
printf("[%s] create file:%s failed\n", __func__, name);
return;
}
printf("[%s] create file:%s ok\n", __func__, name);
//先給文件開辟一塊空間
if (-1 == lseek(fd, file_length -1, SEEK_SET))
{
printf("[%s] lseek failed\n", __func__);
goto DONE;
}
if (1 != write(fd, "\0", 1))
{
printf("[%s] write failed\n", __func__);
goto DONE;
}
//將文件映射到虛擬內存
void *fileptr = mmap(NULL, file_length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == fileptr)
{
printf("[%s] mmap failed\n", __func__);
goto DONE;
}
//創建線程
pthread_t threads[MULTI_DOWNLOAD_THEAD_NUM];
//ThreadParam threadParam[MULTI_DOWNLOAD_THEAD_NUM];
for (int i = 0; i < MULTI_DOWNLOAD_THEAD_NUM; i++)
{
threadParam[i].thrd_num = (i+1);
threadParam[i].url = (char *)url;
threadParam[i].range[0] = (file_length / MULTI_DOWNLOAD_THEAD_NUM) * i;
threadParam[i].range[1] = (MULTI_DOWNLOAD_THEAD_NUM - 1 == i) ? (file_length - 1) : (file_length / MULTI_DOWNLOAD_THEAD_NUM) * (i + 1) - 1;
threadParam[i].ptr = fileptr + threadParam[i].range[0];
threadParam[i].offset = 0;
pthread_create(&threads[i], NULL, thread_func, &threadParam[i]);
}
for (int i = 0; i < MULTI_DOWNLOAD_THEAD_NUM; i++)
{
pthread_join(threads[i], NULL);
}
printf("[%s] all download done\n", __func__);
munmap(fileptr, file_length);
DONE:
printf("[%s] close file\n", __func__);
close(fd);
printf("[%s] out\n", __func__);
}
mmap 是 Unix/Linux 系統中用于將文件或設備映射到進程虛擬內存空間的系統調用,其函數原型如下:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
參數:
void *addr:期望的映射起始地址(通常設為 NULL,由操作系統自動選擇合適的地址)
size_t length:要映射的字節數(必須大于 0),通常是文件的大小
int prot:映射區域的保護權限(內存訪問權限),可組合以下值:
PROT_READ:可讀(必須有,否則無法訪問映射區域)PROT_WRITE:可寫(修改映射區域會同步到文件)PROT_EXEC:可執行(映射區域的內容可作為代碼運行)PROT_NONE:不可訪問(無任何權限)int flags:映射類型和屬性,關鍵取值(必選其一):
MAP_ANONYMOUS:匿名映射(無關聯文件,用于進程間共享內存),此時 fd 需設為 -1MAP_FIXED:強制使用 addr 作為起始地址(若無法映射會失敗,不推薦隨意使用)MAP_SHARED:共享映射。修改映射區域會同步到文件,且對其他映射該文件的進程可見
MAP_PRIVATE:私有映射。修改映射區域不會同步到文件,僅創建進程可見(寫時復制)
其他常用標志:
int fd:要映射的文件描述符(通過 open 打開的文件句柄)
off_t offset:從文件的哪個偏移量開始映射(必須是系統頁大小的整數倍,通常為 4KB 或 8KB)
返回值:
void* 指針)MAP_FAILED(通常是 (void*)-1),并設置 errno 指示錯誤原因,例如:EBADF 表示文件描述符無效EACCES 表示權限不足假設數據的長度為file_length,有N個線程進行同時下載,則將數據平均分為N份(0、1、...、N-1),由于可能無法正好平均分,則最后一份剩余多少就是多少。

獲取文件長度的原理,也是通過curl來執行一次數據傳輸,只不過,不是獲取數據本身,只是獲取數據頭數據,然后通過curl_easy_getinfo來獲取數據頭中包含的數據長度信息。
long long get_download_length(const char *url)
{
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"); //opt(about://version)
curl_easy_setopt(curl, CURLOPT_HEADER, 1); //opt
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
if (CURLM_OK != curl_easy_perform(curl))
{
printf("[%s] failed\n", __func__);
return-1;
}
double res = 0; //double類型
curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &res);
download_len = (longlong )res;
return download_len;
}
線程函數的內容,其實就是在單線程下載的示例程序中的那些curl的接口調用邏輯。
主要調用的接口如下:
void *thread_func(void *arg)
{
ThreadParam *par = (ThreadParam *)arg;
char range[64] = {0};
sprintf(range, "%lld-%lld", par->range[0], par->range[1]);
//創建一個curl對象
printf("[%s] thrd<%d> curl init\n", __func__, par->thrd_num);
CURL *curl = curl_easy_init();
printf("[%s] thrd<%d> curl setopt, url:%s, range:%s\n", __func__, par->thrd_num, par->url, range);
curl_easy_setopt(curl, CURLOPT_URL, par->url);
curl_easy_setopt(curl, CURLOPT_RANGE, range);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, par);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, download_progress_cb);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, par);
//執行網絡請求
printf("[%s] thrd<%d> curl performt\n", __func__, par->thrd_num);
CURLcode res = curl_easy_perform(curl);
if (CURLE_OK != res)
{
printf("[%s] thrd<%d> curl_easy_perform err:%d\n", __func__, par->thrd_num, res);
}
printf("[%s] thrd<%d> curl performt done\n", __func__, par->thrd_num);
}
這里curl_easy_setopt新增了對下載數據進度的回調邏輯,可以在下載文件的過程中,顯示下載的進度
下載數據的回調,需要根據回調函數的原型,自己實現具體的內容,這里就是將接收的數據通過memcpy方法寫入自己創建的文件。
size_t write_file_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
{
static int i = 0;
size_t this_size = size * nmemb;
//printf("[%s] <%d> total size:%zu\n", __func__, ++i, this_size);
ThreadParam *par = (ThreadParam *)userdata;
memcpy(par->ptr + par->offset, ptr, this_size);
par->offset += this_size;
return this_size;
}
下載進度的回調,需要根據回調函數的原型,自己實現具體的內容。
int download_progress_cb(void *userdata, double totalDownload, double nowDownload, double totalUpload, double nowUpload)
{
ThreadParam *par = (ThreadParam *)userdata;
par->download = nowDownload;
int percent = 0;
staticint lastPercent = -1;
if (totalDownload > 0)
{
double allDownload = 0;
for (int i = 0 ;i < MULTI_DOWNLOAD_THEAD_NUM; i++)
{
allDownload += threadParam[i].download;
}
percent = (int)(allDownload / download_len * 100);
}
if (lastPercent != percent)
{
lastPercent = percent;
printf("[%s] percent:%d%%\n", __func__, percent);
}
return0;
}
主函數的內容如下:
// gcc download_file_multi_thread.c -o download_file_multi_thread -lcurl -lpthread
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <time.h>
#include <pthread.h>
constchar *file_url = "https://vscode.download.prss.microsoft.com/dbazure/download/stable/488a1f239235055e34e673291fb8d8c810886f81/code_1.102.3-1753759567_amd64.deb";
constchar *file_name = "my_multithread_download.deb";
#define MULTI_DOWNLOAD_THEAD_NUM (3)
typedefstruct
{
int thrd_num;
char *url;
longlong range[2];
char *ptr;
int offset;
double download;
}ThreadParam;
ThreadParam threadParam[MULTI_DOWNLOAD_THEAD_NUM];
longlong download_len = -1;
size_t write_file_cb(char *ptr, size_t size, size_t nmemb, void *userdata);
int download_progress_cb(void *userdata, double totalDownload, double nowDownload, double totalUpload, double nowUpload);
long long get_download_length(const char *url);
void *thread_func(void *arg);
void http_file_download(const char *url, const char *name);
int main()
{
printf("hello\n");
time_t start;
time_t end;
time(&start);
http_file_download(file_url, file_name);
time(&end);
int esapsed = difftime(end, start);
printf("esapsed time:%d sec\n", esapsed);
return0;
}
運行結果如下:


可以看到,3個線程的下載依次完成,進度最終顯示到100%,文件下載完成。
不過,通過計時打印,多個線程下載,總耗時卻沒有減少,有待再研究。
本篇介紹了如何使用curl編程實現文件的下載,首先介紹了curl編程的一些基礎API的使用,然后通過實例編程,來實現一個文件下載的功能。