C++之Libcurl庫實現HTTP協議傳輸數據

        一直想寫一些關於C++的博客,卻一直沒抽空來寫,今天趁着代碼打累了,來寫寫年前想寫的博客。       
        在做項目時,因爲我使用的後臺是用.net core寫的,那麼C++就需要使用http協議來同後臺進行交互了。C++要如何使用http協議呢?這裏我推薦使用Libcurl這個庫,不得不說這個庫真的很強大(有興趣的小夥伴可以去查閱查閱),當然也可以使用其他的,下面我們進入正題。
       首先大家先到網上下載libcurl,大家自行下載,密碼:zsrb,博主這裏用的是curl-7.26.0的,將“curl-7.26.0/include/curl文件夾拷貝到自己的項目中,該文件夾包含了curl需要的頭文件,爲了方便起見我將curl的庫文件也拷貝到了項目中,並放在了剛剛的curl中,庫文件的地址“curl-7.26.0/lib/Debug”和"curl-7.26.0/lib/Release"。下面我們在項目中引入curl:  
//引入頭文件
#include "curl\curl.h"
#include "curl\easy.h"
下面我們就來說說curl的使用。
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();

curl_global_init()用以初始化curl環境,curl_easy_init用來初始化一個easy curl對象。

#ifdef _DEBUG
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
#endif
    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);	
    curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);

curl_easy_setopt是對easy curl對象進行相關設置,需要設置哪些參數可以自行查閱。這事可以直接使用curl_easy_perform執行curl請求,但這種情況是阻塞的,所以下面我會介紹multi執行併發請求。先來看看代碼

bool CLibcurl::UserLand(const std::string number, const std::string password)
{
	std::string  strUrl = "http://*******/User/Login";        // 接口地址
	CURL *curl;
	CURLM *multi_handle;
	std::stringstream getstream;
	int still_running;
	bool IsTrue = false;

	struct curl_httppost *formpost = NULL;
	struct curl_httppost *lastptr = NULL;
	struct curl_slist	 *headers = NULL;
	static const char buf[] = "Expect:";
	curl_global_init(CURL_GLOBAL_ALL);
	curl_formadd(&formpost, &lastptr,
		CURLFORM_COPYNAME, "username",
		CURLFORM_COPYCONTENTS, number.c_str(),
		CURLFORM_END);
	curl_formadd(&formpost, &lastptr,
		CURLFORM_COPYNAME, "password",
		CURLFORM_COPYCONTENTS, password.c_str(),
		CURLFORM_END);
		
	curl = curl_easy_init();
	multi_handle = curl_multi_init();
	if (NULL == curl || NULL == multi_handle) {		
		IsTrue = false;
		goto exit;
	}			

	headers = curl_slist_append(headers, buf);
#ifdef _DEBUG
	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
#endif
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);	
	curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);    // 表單
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &getstream);

	curl_multi_add_handle(multi_handle, curl);

	while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle, &still_running));
	while (still_running) {
			
		switch (Select(multi_handle)) {
		case -1:
			break;
		case 0:
			std::cout << "timeout" << std::endl;
		default:
			while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle, &still_running));
			break;
		}
	}

	//對接收到的getstream進行處理

exit:	
	curl_global_cleanup();
	curl_multi_cleanup(multi_handle);
	curl_easy_cleanup(curl);
	curl_formfree(formpost);
	curl_slist_free_all(headers);

	return IsTrue;
}

下面我們來分析下這個代碼,此處我寫的是一個簡單的提交登陸表單的程序,使用curl_formadd()來構建表單,是不是發現表單構建起來變得很簡單了,突然有了寫javascript的感覺。curl_formadd中的 CURLFORM_COPYNAME,是後臺接收時的字段名,而CURLFORM_COPYCONTENTS則是存儲字段名對應的內容,比如用戶的用戶名,想了解更多可點擊該鏈接。 使用multi前我們還需要用curl_multi_init()先初始化multi,雖然說multi是併發的,但其實它的使用也是非常簡單的,只需將我們上面使用curl_easy_init創建的curl傳入到curl_slist_append的第二個參數中就行了,接下來我們就可以用curl_multi_perform執行multi了,此處使用的是select來對事件進行監聽,並通知curl執行對應操作。

上面代碼中的Select函數代碼如下:

int CLibcurl::Select(CURLM *multi_handle)
{
	struct timeval timeout;
	int rc;
	fd_set fdread;
	fd_set fdwrite;
	fd_set fdexcep;
	int maxfd;
	FD_ZERO(&fdread);
	FD_ZERO(&fdwrite);
	FD_ZERO(&fdexcep);

	timeout.tv_sec = 1;
	timeout.tv_usec = 0;

	// 獲取文件描述符
	curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
	rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);

	return rc;
}

最後補充下,在構建表單的時候可以將文件傳入表單中

curl_formadd(&formpost, &lastptr, 
	CURLFORM_COPYNAME, "data",
	CURLFORM_FILE, filepath.c_str(),        // 文件的所在地址
	CURLFORM_END);
可以用這種方法來實現小文件的簡單上傳,curl的用法大致就說到這裏了,想深入研究的朋友可以積極查閱資料。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章