libcurl出现CURLcode 23 CURLE_WRITE_ERROR错误

本文介绍了解决使用libCURL进行HTTP请求时遇到的CURLE_WRITE_ERROR问题。问题出现在自定义写入函数中,返回值应为实际写入的字节数而非固定值0。通过修改写入函数返回值解决了此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用libCURL时调用curl_easy_perform返回的CURLcode为23错误。
查看得知是CURLE_WRITE_ERROR,写文件错误。
估计是使用curl_easy_setopt时设置CURLOPT_WRITEFUNCTION或者CURLWRITEDATA时有问题,结果找了半天也没有发现。
最后发现是够早的WRITEFUNC有问题:
错误:
size_t function(const void *ptr, size_t size, size_t nmemb, const void *stream)
     … … … …
     fwrite(ptr, size, nmemb, (FILE *)stream);
     … … … …
     return 0;
}
返回值出错,正确的返回值应该是文件写入的大小
return size * nmemb;
否则就会报上面的错误。
正确函数:
size_t function(const void *ptr, size_t size, size_t nmemb, const void *stream)
     int ret;
     … … … …
     ret = fwrite(ptr, size, nmemb, (FILE *)stream);
     … … … …
     return ret;
}
这样,在fwrite正确执行时,就不会报错了。
<think>我们正在讨论libcurl的写回调函数(writecallback function)。用户请求一个关于curl_write_callback的示例用法。根据引用内容,我们知道libcurl是一个用于传输数据的库,支持多种协议。在使用libcurl进行数据传输时,当我们使用curl_easy_perform()执行传输时,接收到的数据默认会打印到标准输出。但如果我们想将数据存储到内存或文件中,就需要设置写回调函数。写回调函数的原型为: ```csize_twrite_callback(char*ptr, size_t size, size_t nmemb,void *userdata); ```其中:- `ptr`:指向接收到的数据的指针。 -`size`:总是1(根据官方文档,这个参数是每个数据块的大小,但通常我们使用`size*nmemb`作为总数据大小)。 -`nmemb`:接收到的数据块的数量(即数据长度)。 -`userdata`:用户自定义数据,通过`CURLOPT_WRITEDATA`设置。 回调函数应该返回实际处理的数据字节数(通常就是`size* nmemb`),如果返回的值与传入的大小不一致,libcurl会认为出错并终止传输。下面是一个示例,展示如何使用写回调函数将获取的数据存储到一个内存缓冲区中: ```c#include <stdio.h> #include<stdlib.h>#include <string.h> #include<curl/curl.h>//写回调函数size_twrite_callback(char*ptr, size_t size, size_t nmemb,void *userdata) {size_t total_size =size *nmemb;//假设userdata是一个指向我们自定义结构的指针,该结构包含一个字符串指针和当前大小//这里为了简单,我们假设userdata是一个文件流FILE*stream= (FILE *)userdata;if (!stream){printf("Error: nostream.\n");return0;}//将数据写入文件流size_t written= fwrite(ptr,size,nmemb, stream);return written;} intmain(intargc,char *argv[]){CURL*curl;CURLcode res;if (argc!=2){printf("Usage:%s<url>\n", argv[0]);return1;}//打开文件用于保存数据FILE *fp =fopen("output.html", "wb");if(!fp) {printf("Couldnot openfile forwriting.\n");return1;}curl =curl_easy_init();if (curl){//设置URLcurl_easy_setopt(curl,CURLOPT_URL, argv[1]);//设置写回调函数curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION, write_callback);//设置传递给回调函数的用户数据(这里传递文件流)curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);//执行请求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);}//关闭文件fclose(fp);return0;} ```在这个例子中:1.我们定义了一个写回调函数`write_callback`,它使用`fwrite`将数据写入文件流。2.在`main`函数中,我们打开一个文件("output.html")用于写入。 3.使用`curl_easy_setopt`设置回调函数(`CURLOPT_WRITEFUNCTION`)和用户数据(`CURLOPT_WRITEDATA`),这里用户数据是文件指针。4.执行传输后,数据会被写入文件中。 如果用户希望将数据存储到内存中(例如字符串),可以这样修改回调函数和主程序:```c//自定义结构用于存储数据structMemoryStruct{char *memory;size_t size; };//写回调函数(用于内存)size_twrite_memory_callback(char*ptr, size_t size, size_t nmemb,void *userdata) {size_t total_size =size *nmemb;struct MemoryStruct *mem =(structMemoryStruct*)userdata;//重新分配内存,包括新数据的大小char *new_memory =realloc(mem->memory, mem->size+ total_size +1);if (!new_memory){printf("Not enoughmemory (reallocreturned NULL)\n");return0;}mem->memory= new_memory;memcpy(&(mem->memory[mem->size]),ptr,total_size);mem->size +=total_size;mem->memory[mem->size]= '\0';//添加字符串结束符return total_size;} //在main函数中使用:int main(intargc,char *argv[]){// ...省略前面的代码...struct MemoryStruct chunk={0}; //初始化为0curl =curl_easy_init();if (curl){//设置URLcurl_easy_setopt(curl, CURLOPT_URL,argv[1]);//设置写回调函数(内存版本)curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION, write_memory_callback);//设置用户数据,传递chunk结构curl_easy_setopt(curl,CURLOPT_WRITEDATA,(void*)&chunk);res= curl_easy_perform(curl);if (res !=CURLE_OK){fprintf(stderr,"curl_easy_perform() failed: %s\n", curl_easy_strerror(res));}else {//使用chunk.memory中的数据,例如打印到控制台printf("%s\n",chunk.memory);}curl_easy_cleanup(curl);//释放内存free(chunk.memory);}return0;} ```在这个内存版本中,我们定义了一个结构`MemoryStruct`来存储数据和当前大小。回调函数中,我们使用`realloc`动态扩展内存,并将新数据追加到内存中,最后添加一个空字符使其成为C字符串。注意事项: -回调函数必须返回实际处理的数据大小(即`size *nmemb`),否则libcurl会终止传输。 -在内存版本中,记得在最后释放分配的内存。用户可以根据需要选择将数据写入文件还是内存。相关问题: 1.如何设置libcurl的读回调函数(用于上传数据)?2.如何处理libcurl传输过程中的错误?3.如何设置libcurl的HTTP请求头?</think>### libcurl 写回调函数(curl_write_callback)示例与用法 #### 基本概念 在 libcurl 中,`curl_write_callback` 是处理接收数据的自定义函数。当使用 `curl_easy_perform()` 执行请求时,接收到的数据会通过此回调函数处理。通过设置 `CURLOPT_WRITEFUNCTION` 和 `CURLOPT_WRITEDATA` 选项,可自定义数据处理逻辑[^1]。 #### 回调函数原型 ```c size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata); ``` - **`ptr`**:指向接收数据的缓冲区 - **`size * nmemb`**:数据总大小(`size` 通常为 1,`nmemb` 为数据长度) - **`userdata`**:通过 `CURLOPT_WRITEDATA` 设置的自定义指针 - **返回值**:实际处理的数据量(必须等于 `size * nmemb`,否则会中断传输) --- ### 示例用法 #### 示例 1:将数据保存到文件 ```c #include <curl/curl.h> #include <stdio.h> // 写回调函数 size_t write_to_file(char *ptr, size_t size, size_t nmemb, void *stream) { size_t written = fwrite(ptr, size, nmemb, (FILE *)stream); return written; // 返回实际写入的字节数 } int main(void) { CURL *curl = curl_easy_init(); if (curl) { FILE *fp = fopen("output.html", "wb"); // 打开文件 curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_file); // 设置回调 curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); // 传递文件指针 CURLcode res = curl_easy_perform(curl); // 执行请求 fclose(fp); // 关闭文件 curl_easy_cleanup(curl); // 清理资源 } return 0; } ``` #### 示例 2:将数据保存到内存 ```c #include <curl/curl.h> #include <stdlib.h> struct MemoryBuffer { char *data; size_t size; }; // 写回调函数(内存存储) size_t write_to_memory(char *ptr, size_t size, size_t nmemb, void *userdata) { size_t total_size = size * nmemb; struct MemoryBuffer *mem = (struct MemoryBuffer *)userdata; // 扩展内存并追加数据 char *new_data = realloc(mem->data, mem->size + total_size + 1); if (!new_data) return 0; // 内存分配失败 mem->data = new_data; memcpy(&(mem->data[mem->size]), ptr, total_size); mem->size += total_size; mem->data[mem->size] = '\0'; // 添加终止符 return total_size; } int main(void) { CURL *curl = curl_easy_init(); if (curl) { struct MemoryBuffer chunk = {0}; // 初始化缓冲区 curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_memory); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk); // 传递缓冲区指针 curl_easy_perform(curl); printf("Received %zu bytes:\n%.*s\n", chunk.size, (int)chunk.size, chunk.data); free(chunk.data); // 释放内存 curl_easy_cleanup(curl); } return 0; } ``` --- ### 关键点说明 1. **回调函数必须返回实际处理的数据量** 若返回值与 `size * nmemb` 不一致,libcurl 会终止传输(常用于错误处理)。 2. **`CURLOPT_WRITEDATA` 传递自定义数据** 可传递 `FILE*`、内存结构指针、类对象指针等,实现灵活的数据处理[^2]。 3. **错误处理建议** ```c size_t write_callback(...) { if (/* 磁盘空间不足 */) return 0; // 返回0会中断传输 // ... } ``` 4. **性能优化** - 避免在回调中执行复杂操作 - 预分配内存(如示例 2 的 `realloc` 策略) - 使用 `CURLOPT_BUFFERSIZE` 调整接收缓冲区大小 --- ### 常见问题解决 **Q: 回调函数未被调用?** A: 检查是否正确设置: - `CURLOPT_WRITEFUNCTION` 指向有效函数 - `CURLOPT_WRITEDATA` 已赋值 - URL 有效且网络可达 **Q: 数据不完整?** A: 确保回调函数返回 `size * nmemb` 值,否则 libcurl 会丢弃未处理的数据。 **Q: 内存泄漏?** A: 在 `curl_easy_cleanup()` 后释放 `CURLOPT_WRITEDATA` 分配的资源(如示例 2 的 `free(chunk.data)`)[^3]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值