当前位置: 首页 > news >正文

libcurl简单使用

libcurl库的使用

1. libcurl库的编译

  • 下载curl-7.77.0.tar.gz,进行解压

    注意版本,否则可能存在编译问题

  • 执行./configure

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意指定项:

可以从docs目录下的install.md文件中查看具体详情

在这里插入图片描述

如果报错:

在这里插入图片描述

附加选项即可,比如--with-wolfssl

在这里插入图片描述

  • 接下来执行makemake install

在这里插入图片描述

出现_install目录即正确

总结:
./configure --prefix=$HOME
make
make install

2.libcurl库使用

通过libcurl的Easy interface API,开发者可以轻松地进行网络通信

主要使用:

#初始化和清理
curl_easy_init()
curl_easy_cleanup()
#设置url和选项
curl_easy_setopt()
#执行请求
curl_easy_perform()
#错误处理
curl_easy_strerror()
const char *curl_easy_strerror(CURLcode error);
curl_global_init()

函数原型

CURLcode curl_global_init(long flags)
  • 函数返回值为CURLcode类型的错误代码

    • 返回值为CURLE_OK表示初始化成功
    • 其他返回值表示初始化过程中出现了错误。
  • 参数flags是一个标志位,用于设置全局初始化的选项

    • CURL_GLOBAL_ALL: 初始化所有的支持的功能

      包括线程安全、DNS解析、SSL等

    • CURL_GLOBAL_SSL: 只初始化SSL相关的功能

    • CURL_GLOBAL_WIN32: 只适用于Windows平台

    • CURL_GLOBAL_NOTHING: 表示libcurl在全局初始化时不初始化任何功能。

  • curl_easy_init()调用时自动调用curl_global_init()
  • curl_global_cleanup()不是线程安全的,不要在每个线程都调用,在主线程调用
curl_global_cleanup()
void curl_global_cleanup(void);

该函数用于清理和释放libcurl库的全局资源。在程序退出之前,应调用该函数来确保释放libcurl占用的系统资源。

  • curl_global_cleanup()函数应在最后一个curl_easy_cleanup()函数调用之后进行调用。

    全局清理会关闭所有的libcurl句柄和资源

  • 如果没有进行全局初始化curl_global_init(),则无需调用curl_global_cleanup()

    全局清理是可选的


#include <stdio.h>
#include <curl/curl.h>
int main(){//初始化CURLcode res=curl_global_init(CURL_GLOBAL_ALL);if(res != CURLE_OK){//打印错误信息fprintf(stderr,"curl_global_init() fails:%s\n",curl_easy_strerror(res));}else{printf("curl_global_init() successful\n");}//清理curlcurl_global_cleanup();return 0;
}
curl_easy_init()
CURL *curl_easy_init(void);
  • 该函数用于创建并返回一个CURL句柄,用于执行curl请求。
  • 该句柄可以用于执行各种curl请求操作,如发送HTTP请求、获取响应、设置请求选项等。

该函数返回一个指向CURL句柄的指针,如果初始化成功,将返回非NULL的指针;否则返回NULL指针。

curl_easy_cleanup()
void curl_easy_cleanup(CURL *handle);
  • 参数handle是一个指向CURL句柄的指针,表示需要清理和释放的句柄。
  • 如果在程序中有多个CURL句柄,每个句柄都需要调用curl_easy_cleanup()进行清理和释放。

该函数意味着会话的开始,后续所有操作都针对某个指针进行,该指针称为句柄。

curl_easy_setopt()

一个用C写的API函数,用于设置CURL会话的各种选项。

CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);

通过该函数,可以设置URL、请求头、请求方法、超时时间等等。

该函数很重要,curl的所有设置都在该函数内完成

  • handle:CURL会话句柄,即通过curl_easy_init()函数初始化得到的指针。

  • option:要设置的选项,是一个预定义的枚举值,表示需要设置的具体选项。

    一些常见的CURLoption选项的参数

    1. URL相关参数
    2. 调试和信号处理参数
    3. SSL参数
    4. 请求头信息参数
    5. 分类:回调
  • parameter:选项的参数值,根据具体的选项而不同。

分类:请求头信息参数
CURLOPT_HEADER:默认为0。指定写回调函数WRITEFUNCTION是否包含报文的头部信息。
CURLOPT_HTTPHEADER:CURLOPT_HTTPHEADER是一个curl_slist结构体类型的参数,它允许用户自定义HTTP请求的头信息。HTTP头部用于在请求中传递额外的信息,如身份验证凭据、自定义标头字段等
设置:CURLOPT_HTTPHEADER
  • CURLOPT_HTTPHEADER参数允许用户自定义HTTP请求的头信息
  • 通过设置curl_slist结构体来添加和管理自定义的头信息。

在这里插入图片描述

//curl_slist_append用于向curl_slist结构中添加新的字符串元素
struct curl_slist *curl_slist_append(struct curl_slist *list,const char *string);
/*
返回值是一个指向更新后字符串列表的指针:如果添加成功,返回的指针将指向新的字符串列表;如果添加失败,返回的指针将与list参数相同。
*/
//curl_slist是libcurl库中用于存储字符串列表的数据结构。它被定义为一个结构体
struct curl_slist {char *data;           // 字符串数据struct curl_slist *next;  // 指向下一个元素的指针
};
//该函数用于释放整个字符串链表及其节点所占用的内存
void curl_slist_free_all(struct curl_slist *list);

使用完curl_slist结构后,应该使用curl_slist_free_all函数释放链表内存,以避免内存泄漏。


 struct curl_slist *headers = NULL;headers=curl_slist_append(headers,"ACCEPT: application/json");headers=curl_slist_append(headers,"Content-Type: application/json");struct curl_slist *cur=headers;while(cur){printf("%s\n",cur->data);cur=cur->next;}//释放内存curl_slist_free_all(headers);

curl_easy_setopt()函数可以设置多个选项,以满足具体的请求需求。

curl_easy_perform

用于执行通过curl_easy_setopt()函数设置的CURL请求。

CURLcode curl_easy_perform(CURL *handle);

函数返回值:函数返回一个CURLcode枚举类型的结果,用于指示请求执行的状态。

如果返回CURLE_OK,表示请求执行成功;如果返回非零错误码,则表示发生了错误。

  • CURLE_OK: 请求成功完成。
  • CURLE_UNSUPPORTED_PROTOCOL: 不支持的协议,由URL的头部指定。
  • CURLE_COULDNT_CONNECT: 无法连接到远程主机或代理。
  • CURLE_REMOTE_ACCESS_DENIED: 访问被拒绝。
  • CURLE_HTTP_RETURNED_ERROR: HTTP返回错误。
  • CURLE_READ_ERROR: 读取本地文件错误。

在调用curl_easy_perform()之前,必须通过curl_easy_setopt()函数设置所需的选项:如URL、请求头、请求方法、请求体等。

#include <stdio.h>
#include <curl/curl.h>
int main(){//初始化CURL *curl=curl_easy_init();if(curl==NULL){fprintf(stderr,"curl_easy_init() failed\n");return 1;}//设置URLcurl_easy_setopt(curl,CURLOPT_URL,"http://www.baidu.com");//执行CURLcode 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);return 1;}//清理curl_easy_cleanup(curl);return 0;
}

总结:

  • 调用curl_global_init()初始化libcurl,调用curl_global_cleanup()清理全局curl句柄
  • 调用curl_easy_init()函数得到 easy interface型指针
  • 调用curl_easy_setopt()设置传输选项
  • 根据curl_easy_setopt()设置的传输选项,实现回调函数以完成用户特定任务
  • 调用curl_easy_perform()函数完成传输任务
  • 调用curl_easy_cleanup()释放内存

几个应用

get请求

#include <stdio.h>
#include <curl/curl.h>
//c语言不支持bool类型
typedef unsigned int bool;
#define true 1
#define false 0
bool getURL(char* filename){//创建句柄CURL* curl;//文件句柄FILE* fp;//返回状态码CURLcode res;//打开文件失败if((fp=fopen(filename,"w"))==NULL){perror("open file fails!!\n");return false;}//设置HTTP头struct curl_slist* headers=NULL;//Accept是标准的HTTP的头字段curl_slist_append(headers,"Accept:Agent-007");//初始化curl=curl_easy_init();if(curl){//非NULL//设置optcurl_easy_setopt(curl,CURLOPT_HEADER,headers);//改协议头curl_easy_setopt(curl,CURLOPT_URL,"http://www.baidu.com");//指定HTTP请求的目标url/* 设置HTTP响应的头部和正文都写入到同一个文件 *///CURLOPT_WRITEDATA用来接收服务器响应的数据curl_easy_setopt(curl,CURLOPT_WRITEDATA,fp);//作用是将 HTTP 响应头部数据写入指定的位置,而不是响应的主体数据(body)curl_easy_setopt(curl,CURLOPT_HEADERDATA,fp);/*开始执行*/res=curl_easy_perform(curl);if(res!=CURLE_OK){fprintf(stderr,"curl_easy_perform() fails:%s",curl_easy_strerror(res));curl_slist_free_all(headers);curl_easy_cleanup(curl);return false;}}else{//打印错误fprintf(stderr,"curl_easy_init() fails!\n");fclose(fp);return false;}fclose(fp);return true;
}
int main(){getURL("hello.html");return 0;
}
#include <stdio.h>
#include <curl/curl.h>
int main(){CURL *curl;FILE *fp;CURLcode res;//全局初始化curl_global_init(CURL_GLOBAL_DEFAULT);//初始化句柄curl=curl_easy_init();//初始化文件fp=fopen("mm.txt","wb");if(fp==NULL){perror("open files fails\n");return 1;}//成功if(curl){struct curl_slist* headers=NULL;curl_slist_append(headers,"Accept:text/html");curl_easy_setopt(curl,CURLOPT_HEADER,headers);curl_easy_setopt(curl,CURLOPT_URL,"http://cn.bing.com/");//保存正文数据curl_easy_setopt(curl,CURLOPT_WRITEDATA,fp);//保存响应头部数据curl_easy_setopt(curl,CURLOPT_HEADERDATA,fp);/*执行*/res=curl_easy_perform(curl);if(res!=CURLE_OK){//出错fprintf(stderr,"curl_easy_perform() fails:%s\n",curl_easy_strerror(res));}/*清理*/curl_slist_free_all(headers);curl_easy_cleanup(curl);fclose(fp);}else{perror("curl_easy_init() fails\n");;}//全局关闭句柄curl_global_cleanup();return 0;
}

回调函数

CURLOPT_WRITEFUNCTIONCURLOPT_WRITEDATE

在使用 libcurl 进行网络请求时,CURLOPT_WRITEFUNCTIONCURLOPT_WRITEDATA 是用来接收和处理服务器返回数据的两个非常重要的设置项,而它们的核心概念是 回调函数(Callback Function)

也就是说:回调函数是当网页有数据返回时进行数据处理的函数

回调函数你把一个函数地址(指针)传给另一个函数,在特定事件发生时,这个函数会被“回调”执行。

  • 通俗理解:你告诉libcurl,“当你收到数据时,请调用我这个函数来处理这些数据。”
  • 回调函数一般由你自己定义,用于处理异步或框架层的数据。
选项用途
CURLOPT_WRITEFUNCTION设置接收数据的回调函数
CURLOPT_WRITEDATA设置传给回调函数的用户指针(一般用于传递保存数据的变量)
CURLOPT_WRITEFUNCTION

这个选项设置 libcurl在收到数据时应该调用哪个函数

size_t write_callback(char* ptr, size_t size, size_t nmemb, void* userdata);
//ptr: 指向返回的数据缓冲区的指针
//size: 每个元素的大小(通常是1)
//nmemb: 元素个数(所以实际大小是 size * nmemb)
//userdata: 你通过 CURLOPT_WRITEDATA 传入的自定义数据指针
/*返回值:必须返回实际处理的字节数(size * nmemb),否则libcurl会认为写入失败*/
CURLOPT_WRITEDATA

这个选项设置的是传给 write_callback 的最后一个参数 userdata

  • 通常你会把一个 std::string* 或文件指针传进去,用于在回调中存储数据。
  • 例如:你想把返回数据写入 std::string buffer;,就把 &buffer 作为 WRITEDATA
CURLOPT_HEADERFUNCTION,CURLOPT_HEADERDATA
回调函数原型为 :
size_t function( void *ptr, size_t size,size_t nmemb, void *stream); 
libcurl一旦接收到http头部数据后将调用该函数。
CURLOPT_WRITEDATA 传递指针给libcurl,该指针表明CURLOPT_HEADERFUNCTION函数的stream指针的来源。
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
typedef unsigned int bool;
#define true 1
#define false 0
/*回调函数固定格式*/
size_t datafun(char* ptr, size_t size, size_t nmemb, void* userdata) {char buffer[1024]={'\0'};strncpy(buffer,ptr,1024);printf("====================get DATA=======================\n");printf("%s\n",buffer);
}
bool getURL(const char* filename){FILE *fp;CURL *curl;CURLcode res;if((fp=fopen(filename,"w"))== NULL){return false;}/*初始化*/curl=curl_easy_init();if(curl){/*设置属性*/struct curl_slist* headers=NULL;headers=curl_slist_append(headers,"Accept:Agent-007");//HTTPHEADER---别忘了HTTPcurl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);//CURLOPT_URLcurl_easy_setopt(curl,CURLOPT_URL,"http://www.baidu.com");//两个DATAcurl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,datafun);/*执行*/res=curl_easy_perform(curl);if(res != CURLE_OK){fprintf(stderr,"curl_easy_perform() fails:%s",curl_easy_strerror(res));curl_slist_free_all(headers);curl_easy_cleanup(curl);return false;}fclose(fp);curl_slist_free_all(headers);curl_easy_cleanup(curl);return true;}
}
int main(){getURL("mm.html");return 0;
}
size_t headfun(char* ptr, size_t size, size_t nmemb, void* userdata) {char buffer[1024]={'\0'};strncpy(buffer,ptr,1024);printf("====================get head=======================\n");printf("%s\n",buffer);
}curl_easy_setopt(curl,CURLOPT_HEADERFUNCTION,headfun);

get head===
HTTP/1.1 200 OK

相关文章:

  • TeledyneLeCroy在OFC2025 EA展台上展示了其400G/800G的全包围的测试解决方案,满足了UEC联盟和UALINK联盟的技术需求
  • [Java][Leetcode simple]26. 删除有序数组中的重复项
  • 欧拉路与欧拉回路(模板)
  • Java学习笔记(对象)
  • 图形硬件系统
  • FPGA生成随机数的方法
  • InnoDB引擎
  • 红外遥控键
  • RDD转换操作中的 关于数据分区coalesce 和 repartition 的区别
  • 轻量服务器与宝塔
  • 查看YOLO版本的三种方法
  • Rockchip RK3308 开发(二)
  • Ingrees 控制器与 Ingress 资源的区别
  • 移动应用开发的六大设计原则
  • Pygame游戏之躲避游戏
  • Vivado中可新建的工程类型解析
  • Linux基础(查找/打包/压缩文件)
  • 显存优化:梯度检查点Gradient Checkpoint和梯度累积Gradient Accumulation
  • 【嵌入式DIY实例-Arduino篇】-DIY遥控手柄
  • Java SpringMVC与MyBatis整合
  • 波兰关闭俄罗斯驻克拉科夫领事馆
  • 宁德时代港股募资预计最高至50亿美元:90%将投向匈牙利项目
  • 文学花边|对话《借命而生》原著作者石一枫:我给剧打90分
  • 昆明一学校门外小吃摊占满人行道,城管:会在重点时段加强巡查处置
  • 印度一战机在巴基斯坦旁遮普省被击落,飞行员被俘
  • 上汽享道出行完成13亿元C轮融资,已启动港股IPO计划