C++中LibCurl库使用流程及配置详解

LibCurl库使用介绍

libcurl是一个跨平台的开源网络传输库,它支持许多协议,包括HTTP、HTTPS、FTP、FTPS、SCP、SFTP、TFTP、LDAP、以及许多其他协议和文件传输方式。libcurl允许开发者使用C语言编写代码来进行网络通信,并提供了简单易用的API接口。
libcurl的主要特点包括:

  • 跨平台性: 可以在各种操作系统上使用,包括Linux、Windows、macOS等。
  • 多协议支持: 支持多种常用的网络协议,例如HTTP、FTP等,以及安全协议如HTTPS、FTPS等。
  • 功能丰富: 提供了丰富的功能和选项,可以用于各种网络传输需求,如文件上传、下载、POST请求等。
  • 高度可定制性: 提供了大量的选项和回调函数,使开发者能够定制和控制网络通信的细节。
  • 易用性: libcurl的API设计简单直观,容易上手,同时也提供了丰富的文档和示例。
    由于其强大的功能和易用性,libcurl被广泛应用于各种软件和项目中,包括网络爬虫、下载工具、Web服务等。

libcurl使用基本流程

  1. 初始化CURL库: curl_global_init(CURL_GLOBAL_ALL);需要初始化libcurl库,这可以通过调用curl_global_init()函数来完成。该函数在整个程序运行期间只需要调用一次。多线程下最好主动调用该函数以防止在线程中curl_easy_init时多次调用,不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。

    		
    CURLcode curl_global_init(long flags); //这个函数只能用一次。(调用curl_global_cleanup清理后可再次使用初始化)
    //参数:flags
     	//CURL_GLOBAL_ALL: 初始化所有的 libcurl 功能。
     	//CURL_GLOBAL_SSL: 初始化 SSL 相关的功能,如支持 HTTPS 议。
     	//CURL_GLOBAL_WIN32: 在 Windows 平台上初始化一些特定的功能。
     	//CURL_GLOBAL_NOTHING: 不做任何初始化,这种情况下需要手动初始化特定的功能。
    //返回值: CURLcode 类型的错误码,如果初始化成功则返回 CURLE_OK,否则返回其他错误码表示初始化失败
    
    
  2. 获取一个CURL句柄用于本次传输: CURL *curl = curl_easy_init(); 成功,则返回指向新创建的 CURL 句柄的指针;如果出现错误,则返回 NULL。

  3. 设置的传输配置选项: 使用curl_easy_setopt() 函数设置HTTP请求的选项,如URL、请求头、请求体等等。如:

    curl_easy_setopt(curl, CURLOPT_URL, url.data());   // 设置要下载的URL地址
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);   // 设置回调函数以将数据写入文件
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &downloadData);   // 传递包含输出文件指针、进度等的结构体给回调函数
    

    curl_easy_setopt() 函数详解:

    CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
    	//参数:
    	//	- handle: 指向 CURL 句柄的指针,表示要设置选项的 CURL 句柄。
    	//	- option: 枚举类型 CURLoption,表示要设置的选项类型。
    	//	- parameter: 选项对应的参数值,类型根据不同选项而定,既可以是个函数的指针,也可以是某个对象的指针,也可以是个long型的变量
    	常见CURLoption类型(更多CURLoption类型的选项都在curl.h库里有定义,man 也可以查看到):
    		CURLOPT_URL: 设置请求的 URL。
    		CURLOPT_HTTPHEADER: 设置请求头信息。
    		CURLOPT_POSTFIELDS: 设置请求体数据。
    		CURLOPT_TIMEOUT: 设置请求超时时间。
    		CURLOPT_WRITEFUNCTION: 设置写数据回调函数。
    		CURLOPT_WRITEDATA: 设置写数据回调函数的用户数据。
    		CURLOPT_PROXY: 设置代理服务器地址。
    		CURLOPT_SSL_VERIFYPEER: 设置是否验证对等证书。
    		CURLOPT_SSL_VERIFYHOST: 设置是否验证主机名。
    		CURLOPT_CUSTOMREQUEST: 设置自定义请求方法。
    		CURLOPT_USERAGENT: 设置用户代理信息。
    		CURLOPT_VERBOSE: 设置是否输出详细的调试信息。
    		CURLOPT_FOLLOWLOCATION: 设置是否跟随重定向。
    		CURLOPT_COOKIE: 设置请求中的 Cookie。
    		CURLOPT_COOKIEFILE: 设置从文件中读取 Cookie。
    		CURLOPT_COOKIEJAR: 设置保存 Cookie 到文件。
    		CURLOPT_RESUME_FROM: 设置断点续传的起始位置。
    		CURLOPT_LOW_SPEED_LIMIT: 设置低速下载速度限制。
    		CURLOPT_LOW_SPEED_TIME: 设置低速下载持续时间。
    		CURLOPT_CONNECTTIMEOUT: 设置连接超时时间
    	
    	例如:
    	struct curl_slist *headers = NULL;
    	headers = curl_slist_append(headers, "Content-Type: application/json");
    	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);	//设置请求头
    	curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");	//设置 URL
    	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "key1=value1&key2=value2");	//设置请求体
    	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); // 设置请求超时时间,超时时间为10秒
    	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);//设置写数据回调函数
    	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);//设置回调函数用户数据
    	curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy.example.com:8080");	//设置代理
    	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); //设置 SSL 选项, 禁止验证对等证书
    

    部分枚举类型选项对应参数值说明

    • CURLOPT_WRITEFUNCTIONCURLOPT_WRITEDATA: 是配合使用的选项,用于设置写数据回调函数和回调函数的用户数据。
      • CURLOPT_WRITEFUNCTION 选项用于设置一个回调函数,该函数在 libcurl 接收到 HTTP 响应数据时被调用,用于处理接收到的数据。回调函数的原型如下(size_t function( void *ptr, size_t size,size_t nmemb, void *stream);):
        size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata);
        //参数:
        	- ptr 是接收到的数据缓冲区指针,
        	- size 是单个数据块的大小,
        	- nmemb 是数据块的数量,
        	- userdata 是传递给 CURLOPT_WRITEDATA 的用户数据指针。
        //返回值:回调函数返回接收到的数据大小。
        
      • CURLOPT_WRITEDATA 选项用于设置回调函数的用户数据指针,该指针将被传递给回调函数作为其第四个参数。通常情况下,该指针指向一个结构体或对象,用于在回调函数中存储处理过程中需要的状态信息。
    • CURLOPT_HEADERFUNCTIONCURLOPT_HEADERDATA 是 libcurl 中用于处理 HTTP 响应头的选项,回调函数:size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata);,具体用法同上。
    • CURLOPT_READFUNCTIONCURLOPT_READDATA 是 libcurl 中用于处理请求体数据的选项。回调函数:size_t read_callback(char *buffer, size_t size, size_t nitems, void *userdata); 用法同上。
    • CURLOPT_NOPROGRESSCURLOPT_PROGRESSFUNCTIONCURLOPT_PROGRESSDATA用于处理下载进度的选项
      • CURLOPT_NOPROGRESS:该选项用于禁止或启用 libcurl 的内置下载进度条功能。设置为 1 表示禁止内置进度条, 0 表示启用内置进度条,默认0;
      • CURLOPT_PROGRESSFUNCTION:设置一个回调函数,用于在下载过程中更新下载进度。注意:若无需使用额外的用户数据,将 nullptr 作为 CURLOPT_PROGRESSDATA 的参数传递给 libcurl;回调函数的原型如下:
        int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
        //参数:
        	- clientp 是传递给 `CURLOPT_PROGRESSDATA` 的用户数据指针,
        	- dltotal 是预期下载总字节数,
        	- dlnow 是当前已下载字节数,
        	- ultotal 是预期上传总字节数,
        	- ulnow 是当前已上传字节数。
        //返回值:回调函数应该返回 0 以继续下载操作,返回非零值表示终止下载操作。
        
      • CURLOPT_PROGRESSDATA:设置用户数据指针
    • CURLOPT_TIMEOUT,`CURLOPT_CONNECTIONTIMEOUT,用于设置超时时间
      • CURLOPT_TIMEOUT:设置请求的总超时时间,即从发送请求到接收完整响应的总时间。如果在指定的时间内未完成请求,libcurl 将会放弃请求,并返回超时错误。该选项的参数是一个长整型值,表示超时时间的秒数;用于对完整响应时间比较关注的场景,例如下载文件、访问网页等。
      • CURLOPT_CONNECTTIMEOUT:该选项用于设置连接超时时间,即建立连接的时间。如果在指定的时间内未能建立连接,libcurl 将会放弃连接尝试,并返回连接超时错误。该选项的参数也是一个长整型值,表示超时时间的秒数;适用于对连接建立时间比较关注的场景,例如需要快速响应的短连接请求
    • CURLOPT_RANGECURLOPT_RESUME_FROM 是 libcurl 中用于实现断点续传
      • CURLOPT_RANGE:设置 HTTP 请求的范围,即指定需要下载的文件的范围。它的参数是一个字符串,格式为 start-end,表示从文件的 start 字节处开始下载,直到 end 字节结束。如果 end 留空,则表示下载从 start 字节开始到文件末尾。用于指定下载文件的范围,允许下载文件的任意部分内容,不仅仅限于断点续传。
      • CURLOPT_RESUME_FROM:该选项用于设置断点续传的起始位置,即指定从文件的哪个字节处开始继续下载。它的参数是一个长整型值,表示断点续传的起始字节位置,主要用于实现断点续传,指定从文件的指定位置开始继续下载
    • CURLOPT_VERBOSE是 libcurl 中的一个选项,选项值类型:long,用于控制是否打印详细的调试信息。设置为非零值时,libcurl 将打印出大量的调试信息,包括请求和响应的头部、数据传输的详细信息等。这些信息对于调试和排查问题非常有用,但在正常情况下可能会显得冗长。通常不会将 CURLOPT_VERBOSE 设置为非零值,因为打印大量的调试信息会影响程序的性能并增加日志的大小。但在调试和开发阶段,可以将其设置为非零值来帮助排查问题。
  4. 执行请求: CURLcode res = curl_easy_perform(curl); //执行HTTP请求

  5. 处理响应: 根据请求的结果进行相应的处理,如处理响应数据、错误处理等。

    if (res != CURLE_OK) {
        fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
    } else {    // 请求成功,处理响应数据  }
    
    //以下是一些常用的 CURLcode 枚举值,详细的错误描述字符串,可以通过const char *curl_easy_strerror(CURLcode errornum ) 这个函数取得
    CURLE_OK (0): 操作成功完成。
    CURLE_UNSUPPORTED_PROTOCOL (1): 不支持的协议。
    CURLE_URL_MALFORMAT (3): URL 格式错误。
    CURLE_COULDNT_RESOLVE_HOST (6): 无法解析主机名。
    CURLE_COULDNT_CONNECT (7): 无法连接到主机或代理。
    CURLE_OPERATION_TIMEDOUT (28): 操作超时。
    CURLE_SSL_CONNECT_ERROR (35): SSL/TLS 连接错误。
    CURLE_PEER_FAILED_VERIFICATION (51): 对等证书验证失败。
    CURLE_GOT_NOTHING (52): 未收到任何数据。
    CURLE_SEND_ERROR (55): 发送数据时出错。
    CURLE_RECV_ERROR (56): 接收数据时出错。
    CURLE_SSL_CERTPROBLEM (58): 证书问题。
    CURLE_SSL_CIPHER (59): SSL/TLS 密码错误。
    CURLE_SSL_CACERT (60): 未找到合适的 CA 证书。
    CURLE_USE_SSL_FAILED (64): 使用 SSL/TLS 失败。
    
  6. 清理: 执行完HTTP请求后,需要清理资源,包括清理CURL句柄和释放libcurl相关的资源。curl_easy_cleanup(curl);

  7. 全局清理: 在程序结束前,需要对libcurl进行全局清理,释放相关资源。curl_global_cleanup();

代码示例:


#include <stdio.h>
#include <curl/curl.h>


struct DownloadData {
	FILE *file = nullptr; // 声明为 null ;
	s32 fileSize;
	s32 downloaded;
	std::string hash;
	bool isInitialized = false;
};

// 定义写数据回调函数
size_t HttpDownloadService::WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
	// size_t data_size = size * nmemb; // 计算本次写入的数据总大小(size是单个数据块大小,nmemb是块的数量)
   	// 获取传递进来的DownloadData结构体指针
   	struct DownloadData *downloadData = (struct DownloadData *) userp;
   // 将数据块写入文件,返回实际写入的大小
    size_t write_size = fwrite(contents, size, nmemb, downloadData->file);
  	downloadData->downloaded += write_size;  // 更新已下载的总字节数
   	if (downloadData->fileSize > 0) {
     	downloaded = downloadData->downloaded;
        double progress = (double) downloadData->downloaded / downloadData->fileSize * 100; 
        std::cout << " Download fileSize: " << downloadData->fileSize << "  Download Progress: " << progress << "%" << std::endl;
      }
   	return write_size;
}
        
int main() {
      curl_global_init(CURL_GLOBAL_ALL);// 初始化CURL库
      CURL *curl = curl_easy_init();  // 获取一个CURL句柄用于本次传输    
      if (curl) {      
     	const char *outputFileName = "aaa.txt";
        struct DownloadData downloadData;
        // 以二进制写模式打开输出文件
        downloadData.file = fopen(outputFileName, "wb"); // Open the file and get FILE* pointer
        downloadData.fileSize = 7022;  // 预期的总文件大小,字节数
        downloadData.downloaded = 0;    // 已下载的字节数
        downloadData.hash = "8b32dbbdfcffc01ae7ff4cd29c9e4bfa973e9df29a629c80605d374d4237e2ba"; // 预期的下载文件SHA256哈希值
        
        curl_easy_setopt(curl, CURLOPT_URL, “http://example.com”);   // 设置要下载的URL地址
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);   // 设置回调函数以将数据写入文件
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &downloadData);   // 传递包含输出文件指针、进度等的结构体给回调函数
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);   // 启用进度回调
        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, nullptr);  // 进度回调函数可选,这里不使用
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);

      		CURLcode res = curl_easy_perform(curl);  // 执行请求
        if (res != CURLE_OK) {
        	// 请求失败,处理错误
             std::cout << "Download failed: {}: " << curl_easy_strerror(res)<< std::endl;
        } else {
         	// 请求成功,处理响应数据
            logger->Info(SRC_LOC, "Download completed successfully.");
            std::cout << "Download completed successfully. " << std::endl;
            //……eg:对比文件大小和hash检查下载文件是否正常
        }

        curl_easy_cleanup(curl);    // 清理CURL句柄资源
        fclose(downloadData.file); // Close the file
      }
       
    curl_global_cleanup();  // 清理CURL库资源
    return 0;
}
		
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值