libcurl 使用的几个注意事项

简介:

:libcurl 入门指南( the tutorial ): http://curl.haxx.se/libcurl/c/libcurl-tutorial.html

0. 为使用的curl url 加入确定的协议头

原文:
If you specify URL without protocol:// prefix, curl will attempt to guess what protocol you might want. It will then default to HTTP but try other protocols based on often-used host name prefixes. For example, for host names starting with "ftp." curl will assume you want to speak FTP.

1. 把 curl_easy_perform() 回调数据直接写到文件里(FILE *)

原文:
libcurl offers its own default internal callback that will take care of the data if you don't set the callback with CURLOPT_WRITEFUNCTION. It will then simply output the received data to stdout. You can have the default callback write the data to a different file handle by passing a 'FILE *' to a file opened for writing with the CURLOPT_WRITEDATA option.
源代码中的实现:

这样,就能够少写一个回调函数了(喂,你是有多懒啊),示比例如以下

FILE *fp;
fp = fopen("/root/test.bmp", "wb");
...
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
...
fclose(fp);

2. curl_easy_perform 返回值处理

使用 CURLOPT_ERRORBUFFER 保存错误, buf_size=CURL_ERROR_SIZE
或使用 curl_easy_strerror(res) (感觉这个简便)
演示样例:

 /* Perform the request, res will get the return code */ 
 res = curl_easy_perform(curl);
 /* Check for errors */ 
 if(res != CURLE_OK)
 {
   printf("%s curl_easy_perform() error! \n", __FUNCTION__);
   printf("error msg = %s\n",  curl_easy_strerror(res));
  curl_easy_cleanup(curl);
   return -1;
 }

3. 多线程环境配置 CURLOPT_NOSIGNAL

原文:
When using multiple threads you should set the CURLOPT_NOSIGNAL option to 1 for all handles. Everything will or might work fine except that timeouts are not honored during the DNS lookup - which you can work around by building libcurl with c-ares support. c-ares is a library that provides asynchronous name resolves. On some platforms, libcurl simply will not function properly multi-threaded unless this option is set.
对于 CURLOPT_TIMEOUT(默认0), CURLOPT_CONNECTTIMEOUT(默认300)选项:
In unix-like systems, this might cause signals to be used unless CURLOPT_NOSIGNAL is set.

4. 设置 CURLOPT_VERBOSE、CURLOPT_HEADER 的必要性

原文:
There's one golden rule when these things occur: set the CURLOPT_VERBOSE option to 1. It'll cause the library to spew out the entire protocol details it sends, some internal info and some received protocol data as well (especially when using FTP). If you're using HTTP, adding the headers in the received output to study is also a clever way to get a better understanding why the server behaves the way it does. Include headers in the normal body output with CURLOPT_HEADER set 1.
经试验:
设置 curl_easy_setopt(curl, CURLOPT_HEADER, 1L) 后,回调函数会返回 http头相关信息(原本是直接输出到stdout的)。考虑到还要过滤这些信息,所以还是不要设置这个了

5. curl post 注意事项

原文:
Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header. You can disable this header with CURLOPT_HTTPHEADER as usual.
解释:
当使用libcurl的POST方式时,假设POST数据的大小大于1024个字节,libcurl不会直接发送POST请求,而是会分为两步运行请求:
<1> 发送一个请求,该请求头部包括一个Expect: 100-continue的字段,用来询问server是否愿意接受数据
<2> 当接收到从server返回的100-continue的应答后,它才会真正的发起POST请求。将数据发送给server。


对于“100-continue"这个字段,RFC文档(http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3)是这么解释的:
它能够让client在发送请求数据之前去推断server是否愿意接收该数据。假设server愿意接收,client才会真正发送数据,
这么做的原因是假设client直接发送请求数据,可是server又将该请求拒绝的话。这样的行为将带来非常大的资源开销。


所以为了避免这样的情况,libcurl在发送大于1024字节的POST请求时採用了这样的方法,可是相对的,它会引起请求延迟的加大,
另外并非全部的server都会正确处理而且应答”100-continue“,比方lighttpd,就会返回417”Expectation Failed“,造成请求逻辑出错。
解决的方法:

// POST数据的大于1024个字节
struct curl_slist *headerlist = NULL;
static const char buf[] = "Expect:";
headerlist = curl_slist_append(headerlist, buf); /* initalize custom header list */
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); /* set header*/
curl_slist_free_all(headerlist); /* free slist */

6. 回调函数的正确返回

return (size * nmemb);

原因:
Your callback function should return the number of bytes it "took care of". If that is not the exact same amount of bytes that was passed to it, libcurl will abort the operation and return with an error code.

假设回调函数中接收的数据有误,个人感觉能够返回0或者返回你已经处理的数据数。
由于源代码的处理例如以下:

 /* If the previous block of data ended with CR and this block of data is
    just a NL, then the length might be zero */
 // len 为要发送给回调函数的数据长度
 if(len) {
   wrote = data->set.fwrite_func(ptr, 1, len, data->set.out);
 }
 else {
   wrote = len;
 }

if(wrote != len) {
  failf(data, "Failed writing body (%zu != %zu)", wrote, len);
  return CURLE_WRITE_ERROR;
}





本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5320114.html,如需转载请自行联系原作者
相关文章
|
Python
解决PIP时候的timeout问题
解决PIP时候的timeout问题
305 0
|
Cloud Native Java 中间件
如何在一个基座上安装更多的 Koupleless 模块?
通过简单的配置,让模块打包更小,从而在一个基座上安装更多的 Koupleless 模块,进一步降低资源成本。
如何在一个基座上安装更多的 Koupleless 模块?
|
11月前
|
机器学习/深度学习 编解码 监控
近红外和可见光图像融合的ICA变换
近红外(NIR)与可见光图像融合中应用独立成分分析(ICA)变换,是一种基于统计独立特性的图像融合方法,旨在结合可见光图像的纹理细节与近红外图像的光谱 / 辐射信息(如低光照、穿透能力等)。
287 5
|
Kubernetes 网络协议 调度
在K8S中,如何具体实现Pod的IP地址发生变化时,不影响正常服务使用?
在K8S中,如何具体实现Pod的IP地址发生变化时,不影响正常服务使用?
|
存储 关系型数据库 MySQL
软件设计与实现:从概念到产品
【8月更文第21天】在现代软件开发过程中,从概念到产品的转化需要经过多个阶段的设计和规划。本文将重点介绍软件设计的几个关键方面:软件设计概述、架构设计、模块设计、用户界面设计以及数据库设计,并通过一个假设的项目——在线图书管理系统为例进行说明。
1282 1
|
Ubuntu Java Linux
update-alternatives命令如何使用?
【8月更文挑战第5天】update-alternatives命令如何使用?
1608 5
|
XML 分布式计算 资源调度
Hadoop配置文件问题
【7月更文挑战第15天】
400 8
|
SQL 关系型数据库 API
SqlAlchemy 2.0 中文文档(十七)(4)
SqlAlchemy 2.0 中文文档(十七)
321 4
|
机器学习/深度学习 人工智能 自然语言处理
构建未来:AI驱动的自适应学习系统
【5月更文挑战第22天】 随着人工智能技术的迅猛发展,教育领域正在经历一场由数据驱动的革新。本文将探讨AI技术在构建自适应学习系统中的关键作用,分析其如何通过个性化教学方案提高学习效率,并预测未来发展趋势。我们将深入研究机器学习算法如何识别学习者的需求,实时调整教学内容和难度,以及AI如何帮助教师和学生在教育过程中实现更好的互动和反馈。
769 0
|
关系型数据库 MySQL Nacos
【深入浅出Nacos原理及调优】「实战开发专题」采用Docker容器进行部署和搭建Nacos服务以及“坑点”
【深入浅出Nacos原理及调优】「实战开发专题」采用Docker容器进行部署和搭建Nacos服务以及“坑点”
685 1