C++中LibCurl庫的使用教程分享
LibCurl是一個(gè)開源的免費(fèi)的多協(xié)議數(shù)據(jù)傳輸開源庫,該框架具備跨平臺(tái)性,開源免費(fèi),并提供了包括HTTP、FTP、SMTP、POP3等協(xié)議的功能,使用libcurl可以方便地進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)傳輸操作,如發(fā)送HTTP請(qǐng)求、下載文件、發(fā)送電子郵件等。它被廣泛應(yīng)用于各種網(wǎng)絡(luò)應(yīng)用開發(fā)中,特別是涉及到數(shù)據(jù)傳輸?shù)膱?chǎng)景。
下載地址:https://curl.haxx.se/download.html
首先讀者需要自行下載該庫,如下筆者選擇下載curl-8.0.1.zip這個(gè)源代碼版本,讀者可找到如下頁面,并點(diǎn)擊對(duì)應(yīng)版本完成下載,當(dāng)下載好以后讀者可自行將其解壓縮到任意目錄下。

當(dāng)讀者解壓縮后,可打開VS2013 開發(fā)人員命令提示并切換帶該目錄中的curl-8.0.1\winbuild目錄,通過執(zhí)行如下兩條命令即可分別實(shí)現(xiàn)編譯靜態(tài)庫或動(dòng)態(tài)庫,我們以靜態(tài)庫編譯為主,執(zhí)行如下命令讀者可自行等待一段時(shí)間。
- 動(dòng)態(tài)庫: nmake /f Makefile.vc mode=dll VC=13 MACHINE=x86 DEBUG=no
- 靜態(tài)庫: nmake / f Makefile.vc mode = static VC = 13 ENABLE_IDN = no MACHINE = x86 DEBUG = no
這個(gè)庫在編譯通過后會(huì)自動(dòng)生成文件到builds\libcurl-vc13-x86-release-static-ipv6-sspi-schannel目錄內(nèi),讀者可自行打開該目錄,即可看到該目錄內(nèi)的頭文件以及庫目錄文件,如下圖所示;

讀者可自行配置這個(gè)靜態(tài)庫,通常只需要配置include和lib文件即可,該庫的使用很簡單,首先我們需要調(diào)用curl_easy_init()函數(shù)對(duì)CURL對(duì)象進(jìn)行初始化,接著通過調(diào)用curl_easy_setopt()并傳入一個(gè)訪問URL鏈接,當(dāng)訪問成功后則可調(diào)用curl_easy_perform()函數(shù)得到訪問結(jié)果,這就是該庫基本使用方法,如下代碼。
#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include "curl/curl.h"
#pragma comment (lib,"libcurl_a.lib")
#pragma comment (lib,"wldap32.lib")
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"Crypt32.lib")
using namespace std;
int main(int argc, char *argv[])
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "https://www.lyshark.com");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
std::cout << "返回狀態(tài): " << res << std::endl;
system("pause");
return 0;
}運(yùn)行上述代碼,讀者可看到網(wǎng)站www.lyshark.com的源代碼,如下圖所示;

上述代碼中的curl_easy_setopt()函數(shù)第二個(gè)參數(shù)可以使用多種類型的變量定義,我們可以通過傳入不同的常量來定義請(qǐng)求頭中的參數(shù),例如當(dāng)我們需要修改協(xié)議頭時(shí),可以使用CURLOPT_HTTPHEADER常量,并在其后第三個(gè)參數(shù)中傳入該常量所對(duì)應(yīng)的結(jié)構(gòu)即可,這個(gè)結(jié)構(gòu)體定義有許多類型,具體如下下表所示;
| 常量名稱 | 描述 |
|---|---|
| CURLINFO_EFFECTIVE_URL | 最后一個(gè)有效的URL地址 |
| CURLINFO_HTTP_CODE | 最后一個(gè)收到的HTTP代碼 |
| CURLINFO_FILETIME | 遠(yuǎn)程獲取文檔的時(shí)間,如果無法獲取,則返回值為-1 |
| CURLINFO_TOTAL_TIME | 最后一次傳輸所消耗的時(shí)間 |
| CURLINFO_NAMELOOKUP_TIME | 名稱解析所消耗的時(shí)間 |
| CURLINFO_CONNECT_TIME | 建立連接所消耗的時(shí)間 |
| CURLINFO_PRETRANSFER_TIME | 從建立連接到準(zhǔn)備傳輸所使用的時(shí)間 |
| CURLINFO_STARTTRANSFER_TIME | 從建立連接到傳輸開始所使用的時(shí)間 |
| CURLINFO_REDIRECT_TIME | 在事務(wù)傳輸開始前重定向所使用的時(shí)間 |
| CURLINFO_SIZE_UPLOAD | 以字節(jié)為單位返回上傳數(shù)據(jù)量的總值 |
| CURLINFO_SIZE_DOWNLOAD | 以字節(jié)為單位返回下載數(shù)據(jù)量的總值 |
| CURLINFO_SPEED_DOWNLOAD | 平均下載速度 |
| CURLINFO_SPEED_UPLOAD | 平均上傳速度 |
| CURLINFO_HEADER_SIZE | header部分的大小 |
| CURLINFO_HEADER_OUT | 發(fā)送請(qǐng)求的字符串 |
| CURLINFO_REQUEST_SIZE | 在HTTP請(qǐng)求中有問題的請(qǐng)求的大小 |
| CURLINFO_SSL_VERIFYRESULT | 通過設(shè)置CURLOPT_SSL_VERIFYPEER返回的SSL證書驗(yàn)證請(qǐng)求的結(jié)果 |
| CURLINFO_CONTENT_LENGTH_DOWNLOAD | 從Content-Length: field中讀取的下載內(nèi)容長度 |
| CURLINFO_CONTENT_LENGTH_UPLOAD | 上傳內(nèi)容大小的說明 |
| CURLINFO_CONTENT_TYPE | 下載內(nèi)容的Content-Type:值,NULL表示服務(wù)器沒有發(fā)送有效的Content-Type:header |
如下案例是一個(gè)簡單的GET請(qǐng)求封裝,通過調(diào)用GetStatus()函數(shù)實(shí)現(xiàn)對(duì)特定頁面發(fā)起請(qǐng)求的功能,其中curl_slist_append()用于增加新的請(qǐng)求頭數(shù)據(jù),在調(diào)用curl_easy_setopt()函數(shù)時(shí),分別傳入了CURLOPT_HTTPHEADER設(shè)置請(qǐng)求頭,CURLOPT_WRITEFUNCTION設(shè)置回調(diào),CURLINFO_PRIMARY_IP獲取目標(biāo)IP地址,CURLINFO_RESPONSE_CODE獲取目標(biāo)返回代碼,此處的write_data()函數(shù)直接返回0則表示屏蔽所有的頁面輸出內(nèi)容。
#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include "curl/curl.h"
#pragma comment (lib,"libcurl_a.lib")
#pragma comment (lib,"wldap32.lib")
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"Crypt32.lib")
using namespace std;
// 設(shè)置CURLOPT_WRITEFUNCTION回調(diào)函數(shù),返回為空屏蔽輸出
static size_t write_data(char *d, size_t n, size_t l, void *p)
{
return 0;
}
// 獲取網(wǎng)站返回值
void GetStatus(char *UrlPage)
{
CURLcode return_code;
// 初始化模塊
return_code = curl_global_init(CURL_GLOBAL_WIN32);
if (CURLE_OK != return_code)
{
return;
}
// 初始化填充請(qǐng)求頭
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0)");
headers = curl_slist_append(headers, "Referer: https://www.lyshark.com");
// 初始化請(qǐng)求庫
CURL *easy_handle = curl_easy_init();
if (NULL != easy_handle)
{
// CURLOPT_HTTPHEADER 自定義設(shè)置請(qǐng)求頭
curl_easy_setopt(easy_handle, CURLOPT_HTTPHEADER, headers);
// CURLOPT_URL 自定義請(qǐng)求的網(wǎng)站
curl_easy_setopt(easy_handle, CURLOPT_URL, UrlPage);
// CURLOPT_WRITEFUNCTION 設(shè)置回調(diào)函數(shù),屏蔽輸出
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, write_data);
// 執(zhí)行CURL訪問網(wǎng)站
return_code = curl_easy_perform(easy_handle);
char *ipAddress = { 0 };
// CURLINFO_PRIMARY_IP 獲取目標(biāo)IP信息
return_code = curl_easy_getinfo(easy_handle, CURLINFO_PRIMARY_IP, &ipAddress);
if ((CURLE_OK == return_code) && ipAddress)
{
std::cout << "目標(biāo)IP: " << ipAddress << std::endl;
}
long retcode = 0;
// CURLINFO_RESPONSE_CODE 獲取目標(biāo)返回狀態(tài)
return_code = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &retcode);
if ((CURLE_OK == return_code) && retcode)
{
std::cout << "返回狀態(tài)碼: " << retcode << std::endl;
}
}
curl_easy_cleanup(easy_handle);
curl_global_cleanup();
}
int main(int argc, char *argv[])
{
GetStatus("https://www.lyshark.com");
system("pause");
return 0;
}運(yùn)行上述代碼,則可以獲取到www.lyshark.com目標(biāo)主機(jī)的IP地址以及頁面返回狀態(tài),如下圖所示;

當(dāng)然該庫同樣支持POST請(qǐng)求方式,在使用POST請(qǐng)求時(shí)我們可以通過CURLOPT_COOKIEFILE參數(shù)指定Cookie參數(shù),通過CURLOPT_POSTFIELDS指定POST的數(shù)據(jù)集,而如果需要使用代理模式則可以通過CURLOPT_PROXY方式來指定代理地址,
#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include "curl/curl.h"
#pragma comment (lib,"libcurl_a.lib")
#pragma comment (lib,"wldap32.lib")
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"Crypt32.lib")
using namespace std;
bool SendPost(char *Url, char *Cookie, char *PostVal)
{
CURL *curl;
CURLcode res;
// 初始化庫
curl = curl_easy_init();
if (curl)
{
// 設(shè)置請(qǐng)求頭
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0)");
headers = curl_slist_append(headers, "Referer: https://www.lyshark.com");
// 設(shè)置請(qǐng)求頭
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
// 指定URL
curl_easy_setopt(curl, CURLOPT_URL, Url);
// 指定cookie參數(shù)
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, Cookie);
// 指定post內(nèi)容
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, PostVal);
// 是否代理
// curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return true;
}
int main(int argc, char *argv[])
{
// 傳入網(wǎng)址 cookie 以及post參數(shù)
SendPost("https://www.lyshark.com/post.php", "1e12sde342r2", "&logintype=uid&u=xieyan&psw=xxx86");
system("pause");
return 0;
}該函數(shù)的調(diào)用需要有一個(gè)POST結(jié)構(gòu)才可測(cè)試,此處由于我并沒有指定接口所有返回了頁面錯(cuò)誤信息,如下圖所示;

接著繼續(xù)實(shí)現(xiàn)下載頁面到本地的功能,該功能實(shí)現(xiàn)的原理是利用write_data回調(diào)函數(shù),當(dāng)頁面數(shù)據(jù)被讀入到內(nèi)存時(shí)回調(diào)函數(shù)會(huì)被觸發(fā),在該回調(diào)函數(shù)的內(nèi)部通過調(diào)用fwrite函數(shù)將ptr指針中的數(shù)據(jù)保存本地,實(shí)現(xiàn)這段代碼如下所示;
#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include "curl/curl.h"
#pragma comment (lib,"libcurl_a.lib")
#pragma comment (lib,"wldap32.lib")
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"Crypt32.lib")
using namespace std;
FILE *fp;
size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
int written = fwrite(ptr, size, nmemb, (FILE *)fp);
return written;
}
BOOL GetUrl(char *URL, char *FileName)
{
CURL *curl;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, URL);
// 在屏幕打印請(qǐng)求連接過程和返回http數(shù)據(jù)
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// 查找次數(shù),防止查找太深
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1);
// 設(shè)置連接超時(shí)
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
// 接收數(shù)據(jù)時(shí)超時(shí)設(shè)置
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
if ((fp = fopen(FileName, "w")) == NULL)
{
curl_easy_cleanup(curl);
return FALSE;
}
// CURLOPT_WRITEFUNCTION 將后繼的動(dòng)作交給write_data函數(shù)處理
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
return TRUE;
}
int main(int argc, char *argv[])
{
// 下載網(wǎng)頁到本地
GetUrl("https://www.lyshark.com", "./lyshark.html");
system("pause");
return 0;
}當(dāng)讀者運(yùn)行上述程序后,即可將www.lyshark.com網(wǎng)站頁面源碼,下載到本地當(dāng)前目錄下lyshark.html,輸出效果如下圖所示;

為了能解析參數(shù),我們還是需要將頁面源代碼讀入到內(nèi)存中,要實(shí)現(xiàn)這個(gè)需求并不難,首先我們定義一個(gè)std::string容器,然后當(dāng)有新數(shù)據(jù)產(chǎn)生時(shí)觸發(fā)WriteCallback在該函數(shù)內(nèi),我們直接將數(shù)據(jù)拷貝到一個(gè)內(nèi)存指針中,也就是存儲(chǔ)到read_buffer內(nèi),并將該緩沖區(qū)返回給調(diào)用者即可,如下則是完整源代碼。
#define CURL_STATICLIB
#define BUILDING_LIBCURL
#include <iostream>
#include <string>
#include "curl/curl.h"
#pragma comment (lib,"libcurl_a.lib")
#pragma comment (lib,"wldap32.lib")
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"Crypt32.lib")
using namespace std;
// 存儲(chǔ)回調(diào)函數(shù)
size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp)
{
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
// 獲取數(shù)據(jù)并放入string中.
std::string GetUrlPageOfString(std::string url)
{
std::string read_buffer;
CURL *curl;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl)
{
// 忽略證書檢查
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
// 重定向
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
// URL路徑
curl_easy_setopt(curl, CURLOPT_URL, url);
// 查找次數(shù),防止查找太深
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1);
// 連接超時(shí)
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
// 接收數(shù)據(jù)時(shí)超時(shí)設(shè)置
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
// 寫入回調(diào)函數(shù)
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &read_buffer);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
return read_buffer;
}
return "None";
}
int main(int argc, char *argv[])
{
std::string urls = GetUrlPageOfString("https://www.lyshark.com");
std::cout << "接收長度: " << urls.length() << " bytes" << std::endl;
system("pause");
return 0;
}如下圖所示,則是運(yùn)行后輸出內(nèi)存數(shù)據(jù)長度,當(dāng)然我們也可以直接輸出urls中的數(shù)據(jù),也就是網(wǎng)頁的源代碼;

到此這篇關(guān)于C++中LibCurl庫的使用教程分享的文章就介紹到這了,更多相關(guān)C++ LibCurl內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
OpenCV實(shí)現(xiàn)特征檢測(cè)和特征匹配方法匯總
一幅圖像中總存在著其獨(dú)特的像素點(diǎn),這些點(diǎn)我們可以認(rèn)為就是這幅圖像的特征,成為特征點(diǎn),本文主要介紹了OpenCV實(shí)現(xiàn)特征檢測(cè)和特征匹配方法,感興趣的可以了解一下2021-08-08
C++實(shí)現(xiàn)LeetCode(692.前K個(gè)高頻詞)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(692.前K個(gè)高頻詞),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
C語言動(dòng)態(tài)內(nèi)存管理的原理及實(shí)現(xiàn)方法
C語言動(dòng)態(tài)內(nèi)存管理的原理是通過 malloc() 函數(shù)申請(qǐng)一塊連續(xù)的內(nèi)存空間,并返回其地址,通過 free() 函數(shù)釋放該內(nèi)存空間。實(shí)現(xiàn)方法是通過在程序運(yùn)行時(shí)動(dòng)態(tài)地管理內(nèi)存,即在需要內(nèi)存時(shí)申請(qǐng),不需要時(shí)釋放,避免了靜態(tài)內(nèi)存分配的浪費(fèi)和不足2023-04-04
使用Qt實(shí)現(xiàn)旋轉(zhuǎn)動(dòng)畫效果
這篇文章主要為大家詳細(xì)介紹了如何使用Qt實(shí)現(xiàn)旋轉(zhuǎn)動(dòng)畫效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-11-11
安裝OpenMPI來配合C語言程序進(jìn)行并行計(jì)算
這篇文章主要介紹了安裝OpenMPI來配合C語言程序進(jìn)行并行計(jì)算的例子,MPI的全稱是Message Passing Interface即標(biāo)準(zhǔn)消息傳遞界面,可以用于并行計(jì)算,需要的朋友可以參考下2015-11-11

