libcurl 使用记录1(回调函数出错)

本文介绍使用libcurlAPI抓取URL时如何通过CURLOPT_WRITEFUNCTION和CURLOPT_HEADERFUNCTION获取header和body,并解决了回调过程中的core问题。文章还详细讨论了libcurl回调函数的工作原理及其参数设置。

昨天使用libcurl api 进行url抓取,想分别获取header和body 存入字符串进行相应的处理。从官网的用例中找到了写文件、写struct的例子。改造之后发现回调过程中出core。

(1)CURLOPT_WRITEFUNCTION和CURLOPT_HEADERFUNCTION

使用过程中发现,仅实现CURLOPT_WRITEFUNCTION就可以获得header和body。

实现CURLOPT_HEADERFUNCTION仅能获得header本身。

(2)libcurl的回调函数是通过流(stream)的方式进行处理

        static size_t header_callback(void *ptr, size_t size, size_t nmemb, void *userdata)

查看回调函数的声明可以发现 它与fwrite的参数完全一致,所以猜想调用实现也应该一致,还没有看libcurl的源码,有时间可以看一下。

     size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

只要收到数据就会调用回调函数,不是接受完才处理,所以在使用过程中发现回调函数会被调用多次,比如接收到一行heade就会调用一次CURLOPT_HEADERFUNCTION的回调函数。(也可能不是一行,有时间看源码确定一下)调用libcurl的过程中会将本次接收的数据、数据长度、单个字符长度传递给回调函数。

在回调函数中可以对接收的数据进行处理,写到第四个参数userdata中。

(3)libcurl的回调函数的第四个参数

使用之前猜想libcurl本省应该给第四个函数开辟了内存,用户最后通过curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,body); 将数据拷贝从userdata拷贝到body中。

但在使用过程中发现,libcurl本省并不会对userdata进行什么处理(初始化内存),想多了,好像也没法这样做。它仅仅通过一些宏,实现了回调。而我们不可能在回调函数中对userdata的内存进行初始化,因为回调函数会调用多次,每次都初始化我们将无法获得全部数据。

那么这个usedata肯定是我们调用之前就已经被初始化的,对的,就是通过 调用curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,body)的时候, 将body的内存直接初始化给userdata。

刚开始没有调用curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,body) 导致core。

(4)错误记录

上面说了实现CURLOPT_WRITEFUNCTION就可以获得header和body。我在使用过程中开始只想获得header数据,于是定义如下

    curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA,header);

 curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,writer_callback);

处理的过程中发现writer_callback 函数中第四个参数并没有分配内存。猜测应该是CURLOPT_WRITEFUNCTION 还是要通过curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,html); 初始化第四个函数(不知道设置了拿到header就停止任务是不是就可以了。。)。虽然它可以分别获得header和body。

添加

curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,html); 之后,程序正常。拿到了想要的html和header。

使用第三方api还是要多看example


### libcurl 中实现进度条功能的回调函数使用方法 在 libcurl 中,可以通过设置 `CURLOPT_XFERINFOFUNCTION` 或 `CURLOPT_PROGRESSFUNCTION` 回调函数来实现进度条功能。这两个选项允许用户定义一个回调函数,在传输过程中定期被调用以报告进度信息[^1]。 以下是实现进度条功能的详细说明和示例代码: #### 1. 设置进度回调函数 为了启用进度回调功能,需要同时设置以下两个选项: - `CURLOPT_XFERINFOFUNCTION`:指定回调函数。 - `CURLOPT_NOPROGRESS`:将其设置为 `0`,以启用进度回调功能[^2]。 回调函数的原型如下: ```c int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); ``` - `clientp`:用户自定义数据指针,通过 `CURLOPT_XFERINFODATA` 传递。 - `dltotal`:下载总字节数(如果未知,则为 `-1`)。 - `dlnow`:当前已下载字节数。 - `ultotal`:上传总字节数(如果未知,则为 `-1`)。 - `ulnow`:当前已上传字节数。 #### 2. 示例代码 以下是一个完整的示例代码,展示如何使用 libcurl 实现进度条功能: ```c #include <stdio.h> #include <curl/curl.h> // 进度回调函数 int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { if (dltotal <= 0) return 0; // 如果总大小未知,跳过进度显示 int percent = (int)((dlnow / dltotal) * 100); // 计算下载百分比 printf("\rProgress: %3d%%", percent); // 显示进度 fflush(stdout); // 刷新输出缓冲区 return 0; // 返回 0 表示继续传输 } int main(void) { CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_DEFAULT); // 全局初始化 curl = curl_easy_init(); // 创建 easy 句柄 if (curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/largefile.zip"); // 设置目标 URL // 启用进度回调功能 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); // 传递用户自定义数据指针(可选) curl_easy_setopt(curl, CURLOPT_XFERINFODATA, NULL); res = curl_easy_perform(curl); // 执行传输 if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } curl_easy_cleanup(curl); // 清理资源 } curl_global_cleanup(); // 清理全局资源 return 0; } ``` #### 3. 注意事项 - 如果 `dltotal` 或 `ultotal` 的值为 `-1`,表示无法确定传输的总字节数。此时可以考虑仅显示已传输的字节数或不显示百分比。 - 在多线程环境中使用时,确保回调函数是线程安全的[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值