libcurl简单使用

发布于:2025-05-12 ⋅ 阅读:(15) ⋅ 点赞:(0)

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");
    }
    //清理curl
    curl_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;
    }
    //设置URL
    curl_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
        //设置opt
        curl_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---别忘了HTTP
        curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
        //CURLOPT_URL
        curl_easy_setopt(curl,CURLOPT_URL,"http://www.baidu.com");
        //两个DATA
        curl_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