C++中LibCurl庫的使用教程分享
LibCurl是一個開源的免費的多協(xié)議數(shù)據(jù)傳輸開源庫,該框架具備跨平臺性,開源免費,并提供了包括HTTP
、FTP
、SMTP
、POP3
等協(xié)議的功能,使用libcurl
可以方便地進行網(wǎng)絡(luò)數(shù)據(jù)傳輸操作,如發(fā)送HTTP
請求、下載文件、發(fā)送電子郵件等。它被廣泛應(yīng)用于各種網(wǎng)絡(luò)應(yīng)用開發(fā)中,特別是涉及到數(shù)據(jù)傳輸?shù)膱鼍啊?/p>
下載地址:https://curl.haxx.se/download.html
首先讀者需要自行下載該庫,如下筆者選擇下載curl-8.0.1.zip
這個源代碼版本,讀者可找到如下頁面,并點擊對應(yīng)版本完成下載,當(dāng)下載好以后讀者可自行將其解壓縮到任意目錄下。
當(dāng)讀者解壓縮后,可打開VS2013 開發(fā)人員命令提示
并切換帶該目錄中的curl-8.0.1\winbuild
目錄,通過執(zhí)行如下兩條命令即可分別實現(xiàn)編譯靜態(tài)庫或動態(tài)庫,我們以靜態(tài)庫編譯為主,執(zhí)行如下命令讀者可自行等待一段時間。
- 動態(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
這個庫在編譯通過后會自動生成文件到builds\libcurl-vc13-x86-release-static-ipv6-sspi-schannel
目錄內(nèi),讀者可自行打開該目錄,即可看到該目錄內(nèi)的頭文件以及庫目錄文件,如下圖所示;
讀者可自行配置這個靜態(tài)庫,通常只需要配置include
和lib
文件即可,該庫的使用很簡單,首先我們需要調(diào)用curl_easy_init()
函數(shù)對CURL
對象進行初始化,接著通過調(diào)用curl_easy_setopt()
并傳入一個訪問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; }
運行上述代碼,讀者可看到網(wǎng)站www.lyshark.com
的源代碼,如下圖所示;
上述代碼中的curl_easy_setopt()
函數(shù)第二個參數(shù)可以使用多種類型的變量定義,我們可以通過傳入不同的常量來定義請求頭中的參數(shù),例如當(dāng)我們需要修改協(xié)議頭時,可以使用CURLOPT_HTTPHEADER
常量,并在其后第三個參數(shù)中傳入該常量所對應(yīng)的結(jié)構(gòu)即可,這個結(jié)構(gòu)體定義有許多類型,具體如下下表所示;
常量名稱 | 描述 |
---|---|
CURLINFO_EFFECTIVE_URL | 最后一個有效的URL地址 |
CURLINFO_HTTP_CODE | 最后一個收到的HTTP代碼 |
CURLINFO_FILETIME | 遠程獲取文檔的時間,如果無法獲取,則返回值為-1 |
CURLINFO_TOTAL_TIME | 最后一次傳輸所消耗的時間 |
CURLINFO_NAMELOOKUP_TIME | 名稱解析所消耗的時間 |
CURLINFO_CONNECT_TIME | 建立連接所消耗的時間 |
CURLINFO_PRETRANSFER_TIME | 從建立連接到準(zhǔn)備傳輸所使用的時間 |
CURLINFO_STARTTRANSFER_TIME | 從建立連接到傳輸開始所使用的時間 |
CURLINFO_REDIRECT_TIME | 在事務(wù)傳輸開始前重定向所使用的時間 |
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ā)送請求的字符串 |
CURLINFO_REQUEST_SIZE | 在HTTP請求中有問題的請求的大小 |
CURLINFO_SSL_VERIFYRESULT | 通過設(shè)置CURLOPT_SSL_VERIFYPEER返回的SSL證書驗證請求的結(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 |
如下案例是一個簡單的GET
請求封裝,通過調(diào)用GetStatus()
函數(shù)實現(xiàn)對特定頁面發(fā)起請求的功能,其中curl_slist_append()
用于增加新的請求頭數(shù)據(jù),在調(diào)用curl_easy_setopt()
函數(shù)時,分別傳入了CURLOPT_HTTPHEADER
設(shè)置請求頭,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; } // 初始化填充請求頭 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"); // 初始化請求庫 CURL *easy_handle = curl_easy_init(); if (NULL != easy_handle) { // CURLOPT_HTTPHEADER 自定義設(shè)置請求頭 curl_easy_setopt(easy_handle, CURLOPT_HTTPHEADER, headers); // CURLOPT_URL 自定義請求的網(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; }
運行上述代碼,則可以獲取到www.lyshark.com
目標(biāo)主機的IP地址以及頁面返回狀態(tài),如下圖所示;
當(dāng)然該庫同樣支持POST
請求方式,在使用POST
請求時我們可以通過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è)置請求頭 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è)置請求頭 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)用需要有一個POST結(jié)構(gòu)才可測試,此處由于我并沒有指定接口所有返回了頁面錯誤信息,如下圖所示;
接著繼續(xù)實現(xiàn)下載頁面到本地的功能,該功能實現(xiàn)的原理是利用write_data
回調(diào)函數(shù),當(dāng)頁面數(shù)據(jù)被讀入到內(nèi)存時回調(diào)函數(shù)會被觸發(fā),在該回調(diào)函數(shù)的內(nèi)部通過調(diào)用fwrite
函數(shù)將ptr
指針中的數(shù)據(jù)保存本地,實現(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); // 在屏幕打印請求連接過程和返回http數(shù)據(jù) curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // 查找次數(shù),防止查找太深 curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1); // 設(shè)置連接超時 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); // 接收數(shù)據(jù)時超時設(shè)置 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3); if ((fp = fopen(FileName, "w")) == NULL) { curl_easy_cleanup(curl); return FALSE; } // CURLOPT_WRITEFUNCTION 將后繼的動作交給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)讀者運行上述程序后,即可將www.lyshark.com
網(wǎng)站頁面源碼,下載到本地當(dāng)前目錄下lyshark.html
,輸出效果如下圖所示;
為了能解析參數(shù),我們還是需要將頁面源代碼讀入到內(nèi)存中,要實現(xiàn)這個需求并不難,首先我們定義一個std::string
容器,然后當(dāng)有新數(shù)據(jù)產(chǎn)生時觸發(fā)WriteCallback
在該函數(shù)內(nèi),我們直接將數(shù)據(jù)拷貝到一個內(nèi)存指針中,也就是存儲到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; // 存儲回調(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); // 連接超時 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); // 接收數(shù)據(jù)時超時設(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; }
如下圖所示,則是運行后輸出內(nèi)存數(shù)據(jù)長度,當(dāng)然我們也可以直接輸出urls
中的數(shù)據(jù),也就是網(wǎng)頁的源代碼;
到此這篇關(guān)于C++中LibCurl庫的使用教程分享的文章就介紹到這了,更多相關(guān)C++ LibCurl內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++實現(xiàn)枚舉網(wǎng)上鄰居信息的示例詳解
在Windows系統(tǒng)中,通過網(wǎng)絡(luò)鄰居可以方便地查看本地網(wǎng)絡(luò)中的共享資源和計算機,本文將介紹一個簡單的C++程序,使用Windows API枚舉網(wǎng)絡(luò)鄰居信息,并獲取對端名稱、本機名稱、主機名稱以及主機IP等信息,文中通過代碼示例給大家講解非詳細,需要的朋友可以參考下2023-12-12C語言結(jié)構(gòu)體(struct)常見使用方法(細節(jié)問題)
這篇文章主要介紹了C語言結(jié)構(gòu)體(struct)常見使用方法(細節(jié)問題),需要的朋友可以參考下2017-03-03