02Linux下使用libcurl(C语言)来实现http请求(数据保存至内存)(这里可以让你深入了解realloc函数)
其它关于lincurl文章
01Linux下使用libcurl(C语言)来实现http请求(数据保存至文件)(包括下载libcurl)
02Linux下使用libcurl(C语言)来实现http请求(数据保存至内存)(这里可以让你深入了解realloc函数)
这篇是从官网的例子中学习的,里面有非常多例子让我们参考。
libcurl/c/example
前言:
上一篇我们讲到网站服务器的响应保存到文件,这篇是保存到内存的。
1 c语言中realloc()函数的作用
参考:
c语言中realloc()函数解析
realloc作用:调整已有的内存。//非常重要的理解,并不是malloc一样开辟指定大小的内存。
//realloc作用:调整已有的内存。
//理解以下内容:
//1)若已有内存后面有足够的空闲位置,则直接在后面扩展缺少的内存(此时ptr=mem->response);
//2)如若不足,则开辟新的空间并将原来内存的数据拷贝到新内存的前面部分,并且原内存被释放掉。
//注意:如果调用成功,不管当前内存段后面的空闲空间是否满足要求,都会释放掉原来的指针,重新返回一个指针,这就导致1)的两个指针都无法再使用,只能根据返回指针使用,这里为ptr
//并且返回的指针ptr的内存已经由另一个进程管理,不需要我们在free(ptr),类似智能指针,所以这里不再需要free任何内存,只需要realloc
//只能使用返回值ptr
char *ptr = realloc(mem->response, mem->size + realsize + 1);//扩展realsize + 1个字节空间(平时绝大部分都是足够的),ptr指向内存大小为mem->size + realsize + 1
if(ptr == NULL){
return 0; /* out of memory! */
}
了解上面的函数后,对下面的回调函数中的内存处理你就非常简单了。
2 例子数据保存至内存)
对比上一篇,这里只是将对应的回调函数修改即可。
#include <stdio.h>
#include <curl/curl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include <stdlib.h> // for realloc
#include <string.h> // for memcpy
const char *userpwd = "xxxxxx";//登录网站所需的账号密码
const char *requestUrl = "xxxxxx";//要登录的url
//用于存储数据的结构体
struct memory {
char *response;
size_t size;
};
//保存网站服务器响应的信息到内存
static size_t write_data2(void *data, size_t size, size_t nmemb, void *userp){
size_t realsize = size * nmemb;//本次响应数据的实际大小
struct memory *mem = (struct memory *)userp;//获取用户传进的变量
//realloc作用:调整已有的内存。1)若已有内存后面有足够的空闲位置,则直接在后面扩展缺少的内存(此时ptr=mem->response);
//2)如若不足,则开辟新的空间并将原来内存的数据拷贝到新内存的前面部分,并且原内存被释放掉。
//注意:如果调用成功,不管当前内存段后面的空闲空间是否满足要求,都会释放掉原来的指针,重新返回一个指针,这就导致1)的两个指针都无法再使用,只能根据返回指针使用,这里为ptr
//并且返回的指针ptr的内存已经由另一个进程管理,不需要我们在free(ptr),类似智能指针,所以这里不再需要free任何内存,只需要realloc
//只能使用返回值ptr
char *ptr = realloc(mem->response, mem->size + realsize + 1);//扩展realsize + 1个字节空间(平时绝大部分都是足够的),ptr指向内存大小为mem->size + realsize + 1
if(ptr == NULL){
return 0; /* out of memory! */
}
//交给mem->response使用
mem->response = ptr;
//从下标为size的地址开始存储本次的响应数据,数据大小为realsize
memcpy(&(mem->response[mem->size]), data, realsize);
//memcpy_s(&(mem->response[mem->size]), realsize, data, realsize);只有windows下有
mem->size += realsize;//将用户已有的数据大小也累积进去
mem->response[mem->size] = 0;//这里是多次请求时将上一次的数据清掉,当对于项目只需要单次请求的可以注释掉,已经测试过。(但最好留着反正没碍着)
return realsize;
}
//Get请求(默认)
int http_client_request(CURL **handle, const char *url, void *userp){
if (!url) {
return -1;
}
//1 初始化libcurl,设置默认参数
CURLcode return_code;
return_code= curl_global_init(CURL_GLOBAL_ALL);
if (CURLE_OK != return_code) {
printf("curl_global_init failed.\n");
return -1;
}
//2 获取easy handle
*handle = curl_easy_init();
if (!(*handle)) {
printf("curl_easy_init failed.\n");
return -1;
}
//2 通过CURLOPT_URL属性设置url
curl_easy_setopt(*handle,CURLOPT_URL, url);
//注册回调函数write_cb,回调函数将会在接收到数据的时候被调用
//curl_easy_setopt(*handle, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(*handle, CURLOPT_WRITEFUNCTION, write_data2);
//设置写数据的变量
if (userp) {
curl_easy_setopt(*handle, CURLOPT_WRITEDATA, userp);
}
//通过CURLOPT_USERPWD属性来设置用户名与密码。参数是”user:password “的字符串
curl_easy_setopt(*handle,CURLOPT_USERPWD, userpwd);
//3 使用curl_easy_perform执行上传数据
curl_easy_perform(*handle);
//4 任务执行结束使用curl_easy_cleanup把内存释放
curl_easy_cleanup(*handle);
//5 释放libcurl
curl_global_cleanup();
return 0;
}
int main(){
#if 0
CURL *handle;
int fd;
fd = open(saveDataFileName, O_RDWR|O_CREAT);
if(fd == -1){
printf("open file failed.\n");
return -1;
}
int ret = http_client_request(&handle, requestUrl, (void*)&fd);
if(ret == -1){
printf("init client falied.\n");
close(fd);
return -1;
}
close(fd);
#endif
struct memory chunk;
chunk.response = NULL;
chunk.size = 0;
CURL *handle;
int ret = http_client_request(&handle, requestUrl, (void*)&chunk);
if(ret == -1){
printf("init client falied.\n");
return -1;
}
if(chunk.response == NULL){
printf("Get Response Data Failed.\n");
return -1;
}
printf("=====Get Response Data Ok.=====\n");
printf("response_size=%ld\n",chunk.size);
printf("%s",chunk.response);
//可以进一步拷贝至数组
//char jsonBuf[512] = {0};
//memcpy(jsonBuf, chunk.response, chunk.size);
//printf("%s",jsonBuf);
return 0;
}
执行命令和上一篇一样:
gcc curlTest.c -o curlTest -l curl