最近使用学习在C++中使用libcurl,不得不感概PHP是世界上最好的语言,PHP用curl那叫一个省心。Python用起来就要略复杂了,详情可以看我之前的学习笔记《每天进步一点点:Python中使用PycURL访问STEEM RPC》。不过嫌弃PycURL麻烦的可以换Requests等其它库。
但是C++使用libcurl 呢?哎,全是泪水。
(图源 :pixabay)
POST、GET
其实libcurl简单的POST、GET操作还是很简单的
可以参考以下链接:
以POST操作为例:
大致就是初始化、设置参数、执行、清理四个步骤。运行上述代码,我们也可以看到POST的返回内容。但是等等,内容是咋返回的呢?
libcurl 返回数据
默认至stdout
为了找回数据是咋返回的,我搜索了一些文档,不过还是看的迷迷糊糊的,知道我看了这两个页面:
其中CURLOPT_WRITEDATA的说明中提到:
By default, this is a FILE * to stdout.
也就是说数据默认输出到标准输出。这就解释了上述GET、POST示例中并没有使用cout、printf一类的输出操作,我们却可以看到内容。
保存至变量
接下来的问题是,如何将我们要的输出数据保存到变量呢?一种方法是CURLOPT_WRITEDATA中的文件指针换成我们自己的文件,然后输出到文件,(再读回来),如果是下载文件等操作,这种方法还是很便利的。但是如果我们需要在程序中处理数据呢?再读回来的操作显然很傻。
答案是使用CURLOPT_WRITEFUNCTION
以及CURLOPT_WRITEDATA
,当我们设置了CURLOPT_WRITEFUNCTION
,每次我们收到数据后,这个回调函数将会被调用。
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata);
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WRITEFUNCTION, write_callback);
其中ptr
是我们收到数据的指针,数据长度为size*nmemb
,userdata
是由CURLOPT_WRITEDATA
设置的变量,操作方式如下:
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WRITEDATA, void *pointer);
使用CURLOPT_WRITEFUNCTION
需要注意以下几点:
- 回调函数可能被调用不止一次,换句话将数据可能不是一次性返回的
- 每次返回的数据长度为:
size*nmemb
- 回调函数需要返回接收数据的长度,否则会引发
CURLE_WRITE_ERROR
我在这三点上都栽过跟头,希望大家注意别犯和我一样的错误。
保存到变量的例子
libcurl的例子页面,提供了一个将返回数据保存到变量的例子
Shows how the write callback function can be used to download data into a chunk of memory instead of storing it in a file.
例子中定义一个包含指向内存的指针变量,以及接受到的数据长度的变量,然后使用molloc以及realloc以及memcpy来操作内存。这样每次回调函数被调用就会自动计算需要的内存,动态分配,然后复制数据。
这个例子使用了C语言的一些手法来达成这个目的,相对而言比较复杂,需要我们自己管理以及释放内存等。对于文本数据而言,使用string还是超方便的,这里就不再赘述了。