libcurl 笔记
https://curl.haxx.se/libcurl/c/libcurl-tutorial.html
基础
初始化,参数指定要初始化的模块:
1 | curl_global_init(CURL_GLOBAL_ALL); |
如果没有调用 curl_global_init
,curl_easy_perform
会自动调用。
1 | CURL_GLOBAL_WIN32 |
当不再使用 libcurl 时调用:
1 | curl_global_cleanup(); |
init 和 cleanup 避免重复调用,应只调用一次。
查询libcurl支持的特性:
1 | curl_version_info(); |
libcurl 提供两种接口:
- easy interface - 函数以 curl_easy 为前缀,同步、阻塞调用。(let you do single transfers with a synchronous and blocking function call)
- multi interface - 支持在一个线程中多个传输任务,异步。(allows multiple simultaneous transfers in a single thread)
Easy Interface
首先获得一个句柄,该句柄不能被多个线程共享。
1 | easyhandle = curl_easy_init(); |
然后设置选项,用于接下来的传输。设置的选项将一直保持,直到下一次修改。
1 | curl_easy_setopt() |
重置选项:
1 | curl_easy_reset() |
复制句柄,连同其选项:
1 | curl_easy_duphandle() |
常用的选项,比如 URL :
1 | curl_easy_setopt(handle, CURLOPT_URL, "http://domain.com/"); |
大多数选项是字符串,libcurl内部会维护一个字符串的副本。
假设想要接收上面指定的链接收到的数据,可以设置自己的回调函数处理该数据,默认输出到 stdout 。
回调函数:
1 | size_t write_data(void* buffer, size_t size, size_t nmemb, void* userp); |
设置回调函数:
1 | curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, write_data); |
收到数据时,write_data 函数被调用,如果不设置回调函数。
设置回调函数时,第四个参数接收的是自定义数据,比如可以将文件句柄传入第四个参数:
1 | curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &internal_struct); |
选项设置完毕,接下来就是执行任务:
1 | success = curl_easy_perform(easyhandle); |
调用后 libcurl 将连接到远程地址,传输数据,当接收到数据时,之前设置的回调函数会被调用。回调函数会被调用一次或多次,回调函数应返回已处理的字节数,如果不等于传入的字节数 libcurl 将中止传输并返回错误代码。
传输完毕后,可继续使用同一个 handle 继续传输另一个文件,后台 libcurl 会重用连接。
对于某些协议,比如FTP,下载一个文件需要登录、设置传输模式、改变当前目录然后传输文件数据等一系列步骤,libcurl 会自动处理这些步骤,开发人员只需要提供这个需要下载的文件的URL。
libcurl 是线程安全的。
传输可能会因为某些原因失败。
调试用选项:
1 | CURLOPT_VERBOSE |
如果了解某些传输协议,学习协议的 RFC 文档,用利于更好地理解和使用 libcurl。
libcurl 试图使 api 的使用独立于具体的协议,比如使用 FTP 协议上传文件和使用 HTTP 的 PUT 请求上传到 HTTP 服务器使用的 api 调用是相似的。
如同下载,上传数据时,需要一个回调函数提供要上传的数据,调用函数返回0,表示上传结束。
回调函数格式:
1 | size_t read_function(char* bufptr, size_t size, size_t nitems, void* userp); |
设置回调函数:
1 | curl_easy_setopt(easyhandle, CURLOPT_READFUNCTION, read_function); |
设置回调函数第四个参数:
1 | curl_easy_setopt(easyhandle, CURLOPT_READDATA, &filedata); |
设置 libcurl 表明要上传:
1 | curl_easy_setopt(easyhandle, CURLOPT_UPLOAD, 1L); |
某些协议需要知道要上传文件的总大小,file_size 的变量类型必须为 curl_off_t:
1 | curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE_LARGE, file_size); |
当调用 curl_easy_perform()
时,libcurl执行传输。
许多协议需要提供用户名密码才能上传或下载。
libcurl 提供了几种方法来指定用户名密码:
在URL中指定用户名和密码:protocol://user:password@example.com/path/
。
如果在用户名密码中包含奇怪的字符(URL只能包含ASCII字符),需要使用URL编码:%XX,XX为十六进制数字。
使用选项设置用户名密码:
1 | curl_easy_setopt(easyhandle, CURLOPT_USERPWD, "myname:thesecret")`; |
设置代理(proxy)的用户名密码:
1 | curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "myname:thesecret"); |
在 Unix 下用户名密码可以保存在某个配置文件中 $HOME/.netrc
。
可以设置选项使 libcurl 使用配置文件中的用户名和密码:
1 | curl_easy_setopt(easyhandle, CURLOPT_NETRC, 1L); |
配置文件 .netrc 中的内容例如:
1 | machine myhost.mydomain.com |
设置 SSL 私钥密码:
1 | curl_easy_setopt(easyhandle, CURLOPT_KEYPASSWD, "keypassword"); |
HTTP 认证(Authentication)
上文展示了如何设置用户名和密码,当使用 HTTP 协议时,有很多不同的方法提交认证,可以自由控制 libcurl 使用哪一种。
默认的认证方法是“Basic”:明文发送用户名密码,使用 base64 编码,这是不安全的。
目前 libcurl 可以使用以下方法:Basic、Digest、NTLM、Negotiate(SPNEGO)。
可以设置选项告诉 libcurl 使用哪一种:
1 | curl_easy_setopt(easyhandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); |
代理的认证方法 CURLOPT_PROXYAUTH
。
可以使用逻辑或运算符指定多个认证方法,libcurl 将自动选择最安全的一种:
1 | curl_easy_setopt(easyhandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST | CURLAUTH_BASIC); |
也可以使用 CURLAUTH_ANY
。
HTTP POST请求
使用 libcurl 发送如同