之前未曾用过libcurl,只是在postman文档中见过http访问接口是通过libcurl实现的,这次看到同事用其实现的ftp,顿时觉得libcurl在通信中,还是挺万能的,所以我想学一下。
我查过资料后发现它真的支持很多协议:libcurl当前支持http, https, ftp, gopher, telnet, dict, file, 和ldap 协议。还有,它是一个跨平台的网络协议库,在基于LibCurl的程序里,主要采用callback function (回调函数)的形式完成传输任务,用户在启动传输前设置好各类参数和回调函数,当满足条件时libcurl将调用用户的回调函数实现特定功能。
学习libcurl,其实最好看一下官方的文档:libcurl - programming tutorial
基础知识介绍libcurl有两种工作模式:easy interface,此模式是同步,阻塞式的传输,单个传输;
multi interface,此模式是在单个线程同时进行多个传输,它有多线程的优点,但是有不需要承担多线程管理的责任,很是方便。大家可根据不同的需求,选取不同的模式。
easy模式的流程- curl_global_init(long flags) :libcurl初始化,在任何平台使用libcurl的方法之前,必须要用此函数进行先初始化。唯一的参数是为了设置如何初始化的,有以下几个值:默认CURL_GLOBAL_DEFAULT是CURL_GLOBAL_ALL,即初始化所有已知的全部子模块;CURL_GLOBAL_WIN32,只能在windows系统上使用,它会初始化win32 socket ;CURL_GLOBAL_SSL,它会初始化ssl库。
#define CURL_GLOBAL_SSL (1<<0) #define CURL_GLOBAL_WIN32 (1<<1) #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) #define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL
- 获取操作句柄。根据自己的需求,选用不同的模式,获取对应的句柄。
m_pHndCurlEasy = curl_easy_init();
- 传输时,通过curl_easy_setopt设置基本参数,如url地址、http头、cookie信息、发送超时时间等,其中,CURLOPT_URL是必设的选项,格式如下。 第二个参数不同值决定设置不同的参数类型,具体可参考博客:curl库中curl_easy_setopt函数详解_I_O_fly的博客-CSDN博客_curl_easy_setopt
curl_easy_setopt(handle, CURLOPT_URL, "http://domain.com/");
- 设置完成后,调用curl_easy_perform(CURL *curl)函数发送数据,我理解为“开始表演了!!”:基本配置已配置好,开始运转了;
- 数据发送完毕后,调用curl_easy_cleanup清空句柄;
- 不再使用libcurl后,调用curl_global_cleanup()做清理工作。也可以说一个curl_global_init对应一个curl_global_cleanup。
官方示例的网址是:libcurl - source code examples
可以将官方示例下载下来,看看在各种场合的用法。
这里我贴一个ftp通配符下载文件的示例(ftp-wildcard),可以看出与我上方介绍的流程是一致的(easy模式)。
#include结束语#include struct callback_data { FILE *output; }; static long file_is_coming(struct curl_fileinfo *finfo, struct callback_data *data, int remains); static long file_is_downloaded(struct callback_data *data); static size_t write_it(char *buff, size_t size, size_t nmemb, void *cb_data); int main(int argc, char **argv) { CURL *handle; struct callback_data data = { 0 }; int rc = curl_global_init(CURL_GLOBAL_ALL); if(rc) return rc; handle = curl_easy_init(); if(!handle) { curl_global_cleanup(); return CURLE_OUT_OF_MEMORY; } curl_easy_setopt(handle, CURLOPT_WILDCARDMATCH, 1L); curl_easy_setopt(handle, CURLOPT_CHUNK_BGN_FUNCTION, file_is_coming); curl_easy_setopt(handle, CURLOPT_CHUNK_END_FUNCTION, file_is_downloaded); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_it); curl_easy_setopt(handle, CURLOPT_CHUNK_DATA, &data); curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data); if(argc == 2) curl_easy_setopt(handle, CURLOPT_URL, argv[1]); else curl_easy_setopt(handle, CURLOPT_URL, "ftp://example.com/test rc = curl_easy_perform(handle); curl_easy_cleanup(handle); curl_global_cleanup(); return rc; } static long file_is_coming(struct curl_fileinfo *finfo, struct callback_data *data, int remains) { printf("%3d %40s %10luB ", remains, finfo->filename, (unsigned long)finfo->size); switch(finfo->filetype) { case CURLFILETYPE_DIRECTORY: printf(" DIRn"); break; case CURLFILETYPE_FILE: printf("FILE "); break; default: printf("OTHERn"); break; } if(finfo->filetype == CURLFILETYPE_FILE) { if(finfo->size > 50) { printf("SKIPPEDn"); return CURL_CHUNK_BGN_FUNC_SKIP; } data->output = fopen(finfo->filename, "wb"); if(!data->output) { return CURL_CHUNK_BGN_FUNC_FAIL; } } return CURL_CHUNK_BGN_FUNC_OK; } static long file_is_downloaded(struct callback_data *data) { if(data->output) { printf("DOWNLOADEDn"); fclose(data->output); data->output = 0x0; } return CURL_CHUNK_END_FUNC_OK; } static size_t write_it(char *buff, size_t size, size_t nmemb, void *cb_data) { struct callback_data *data = cb_data; size_t written = 0; if(data->output) written = fwrite(buff, size, nmemb, data->output); else written = fwrite(buff, size, nmemb, stdout); return written; }
easy interface是基本的,也是最简单的用法,后续如果有空的话,写一篇multi interface的。



