libcurl的封装,支持同步请求,支持异步通知请求
将libcurl封装了一下
满足同步请求,堵塞操作
也可以异步请求,马上返回,由请求在完成操作之后通知主函数请求已经就绪
闲话不多说,直接上代码
//header #ifndef __HTTP_REQUEST_H #define __HTTP_REQUEST_H #include <string> #include <map> #include <memory> class HttpNotify { public: HttpNotify() {} ~HttpNotify() {} typedef enum { STATE_PROCEEDING, STATE_SUCCESS, STATE_ERROR = -1, }NotifyState; public: virtual void FinishedNotify(bool, const std::string&) = 0; virtual int ProcessCallback(NotifyState state, long size_data, const void* data) = 0; }; //************************************ // Usage: // HttpRequest request; // request.SetRequestUrl("http://www.baidu.com"); // request.SetPostMessage("hello liyanhong"); // request.SetHttpHeader("User-Agent:Mozilla/4.04[en](Win95;I;Nav)"); // request.SetHttpHeader("Range:bytes=554554-"); // request.SetNotifyObject(obj); // /*sync request will block and async request will return immedately*/ // HANDLE hRequest = request.Perform(REQUEST_SYNC); // /*recomment HttpRequest::Close(hRequest) while async request job done*/ // /*sync request will ignore Close*/ //************************************ class HttpRequest { public: typedef enum { REQUEST_SYNC, REQUEST_ASYNC, }RequestType; typedef enum { REQUEST_OK, REQUEST_INVALID_OPT, REQUEST_PERFORM_ERROR, REQUEST_INIT_ERROR, }RequestResult; friend class RequestHelper; HttpRequest(); ~HttpRequest(); void SetRetryTimes(int retry_times = s_kRetryCount); RequestResult SetRequestTimeout(long time_out = 0); RequestResult SetRequestUrl(const std::string& url); RequestResult SetPostMessage(const std::string& message); RequestResult SetHttpHeader(std::map<std::string, std::string>& headers); RequestResult SetHttpHeader(const std::string& header); void SetNotifyObject(HttpNotify* object = NULL); HANDLE Perform(RequestType request_type); static void Close(HANDLE request_handle); bool GetHttpCode(HANDLE request_handle, long* http_code); bool GetReceiveHeader(HANDLE request_handle, std::string* header); bool GetReceiveContent(HANDLE request_handle, std::string* receive); protected: class HttpInternal { public: HttpInternal(); ~HttpInternal(); friend class HttpRequest; friend class RequestHelper; void SetRetryTimes(int retry_times) { m_retry_times = retry_times; } int SetRequestTimeout(long time_out = 0); int SetRequestUrl(const std::string& url); int SetPostMessage(const std::string& message); int SetHttpHeader(const std::string& header); void SetNotify(HttpNotify*); int Perform(); int GetHttpCode() { return m_http_code; } bool GetHeader(std::string* header); bool GetContent(std::string* receive); bool SelfClose(void) { return m_close_self; } private: HANDLE m_curl_handle; HANDLE m_perform_thread; int m_retry_times; std::string receive_content; std::string receive_header; bool m_close_self; HttpNotify* m_notify; HANDLE m_http_headers; long m_http_code; }; private: //HANDLE m_request_handle; std::tr1::shared_ptr<HttpInternal> m_request_handle; static const int s_kRetryCount = 3; }; #endif /*__HTTP_REQUEST_H*/
//cpp #include "stdafx.h" #include <Windows.h> #include "HttpRequest.h" #include "./curl/curl.h" #include <list> #ifdef _DEBUG #pragma comment(lib, "libcurld.lib") #else #pragma comment(lib, "libcurl.lib") #endif #pragma comment(lib, "Wldap32.lib") #pragma comment(lib, "Ws2_32.lib") class RequestHelper { protected: RequestHelper() { curl_global_init(CURL_GLOBAL_DEFAULT); } public: ~RequestHelper() { curl_global_cleanup(); s_async_requests.clear(); } static RequestHelper& Instance() { static RequestHelper the_single_instance; return the_single_instance; } static std::list< std::tr1::shared_ptr<HttpRequest::HttpInternal> > s_async_requests; static DWORD WINAPI PerformThread(LPVOID param) { std::tr1::shared_ptr<HttpRequest::HttpInternal>* request = reinterpret_cast< std::tr1::shared_ptr<HttpRequest::HttpInternal>* >(param); if (request) { (*request)->Perform(); if ((*request)->SelfClose()) { RequestHelper::s_async_requests.remove(*request); } } return 1; } static size_t RetriveHeaderFunction(void *ptr, size_t size, size_t nmemb, void *stream) { std::string* receive_header = (std::string*)stream; if (receive_header && ptr) { receive_header->append(reinterpret_cast<const char*>(ptr), size * nmemb); } return nmemb; } static size_t RetriveContentFunction(void *ptr, size_t size, size_t nmemb, void *stream) { HttpRequest::HttpInternal* request = reinterpret_cast<HttpRequest::HttpInternal* >(stream); if (request && ptr) { std::string* receive = &(request->receive_content); receive->append(reinterpret_cast<const char*>(ptr), size * nmemb); if (request->m_notify) { if (request->m_notify->ProcessCallback(HttpNotify::STATE_PROCEEDING, size*nmemb, ptr) == 0) return 0; //interrupt request process } } return nmemb; } }; std::list< std::tr1::shared_ptr<HttpRequest::HttpInternal> > RequestHelper::s_async_requests; HttpRequest::HttpRequest() : m_request_handle(new HttpInternal) { RequestHelper::Instance(); } HttpRequest::~HttpRequest() { } void HttpRequest::SetRetryTimes(int retry_times) { if (m_request_handle) { m_request_handle->SetRetryTimes(retry_times); } } HttpRequest::RequestResult HttpRequest::SetRequestTimeout(long time_out) { if (m_request_handle) { if (m_request_handle->SetRequestTimeout(time_out) == CURLE_OK) { return REQUEST_OK; } else { return REQUEST_INVALID_OPT; } } return REQUEST_INIT_ERROR; } HttpRequest::RequestResult HttpRequest::SetRequestUrl(const std::string& url) { if (m_request_handle) { if (m_request_handle->SetRequestUrl(url) == CURLE_OK) { return REQUEST_OK; } else { return REQUEST_INVALID_OPT; } } return REQUEST_INIT_ERROR; } HttpRequest::RequestResult HttpRequest::SetPostMessage(const std::string& message) { if (m_request_handle) { if (m_request_handle->SetPostMessage(message) == CURLE_OK) { return REQUEST_OK; } else { return REQUEST_INVALID_OPT; } } return REQUEST_INIT_ERROR; } HttpRequest::RequestResult HttpRequest::SetHttpHeader(std::map<std::string, std::string>& headers) { if (m_request_handle) { std::map<std::string, std::string>::iterator it; for (it = headers.begin(); it != headers.end(); ++it) { std::string header = it->first; header += ":"; header += it->second; if (m_request_handle->SetHttpHeader(header) != CURLE_OK) { return REQUEST_INVALID_OPT; } } return REQUEST_OK; } return REQUEST_INIT_ERROR; } HttpRequest::RequestResult HttpRequest::SetHttpHeader(const std::string& header) { if (m_request_handle) { if (m_request_handle->SetHttpHeader(header) == CURLE_OK) { return REQUEST_OK; } else { return REQUEST_INVALID_OPT; } } return REQUEST_INIT_ERROR; } void HttpRequest::SetNotifyObject(HttpNotify* object) { if (m_request_handle) { m_request_handle->SetNotify(object); } } void HttpRequest::Close(HANDLE request_handle) { std::tr1::shared_ptr<HttpInternal>* request = (reinterpret_cast<std::tr1::shared_ptr<HttpInternal> *>(request_handle)); std::list< std::tr1::shared_ptr<HttpRequest::HttpInternal> >::iterator it; for (it = RequestHelper::s_async_requests.begin(); it != RequestHelper::s_async_requests.end(); ++it) { if ((*request) == *it) { if (WaitForSingleObject((*request)->m_perform_thread, 10) == WAIT_OBJECT_0) { RequestHelper::s_async_requests.remove(*request); } else { (*request)->m_close_self = true; } break; } } } HANDLE HttpRequest::Perform(RequestType request_type) { if (m_request_handle) { if (request_type == REQUEST_SYNC) { m_request_handle->Perform(); return &m_request_handle; } else if (request_type == REQUEST_ASYNC) { DWORD thread_id; RequestHelper::s_async_requests.push_back(m_request_handle); std::tr1::shared_ptr<HttpInternal>& request = RequestHelper::s_async_requests.back(); HANDLE async_thread = CreateThread(NULL, 0, RequestHelper::PerformThread, &(request), 0, &thread_id); Sleep(10); request->m_perform_thread = async_thread; return &request; } return NULL; } return NULL; } bool HttpRequest::GetHttpCode(HANDLE request_handle, long* http_code) { std::tr1::shared_ptr<HttpInternal>* request = reinterpret_cast<std::tr1::shared_ptr<HttpInternal>*>(request_handle); if (request && http_code) { *http_code = (*request)->GetHttpCode(); return true; } return false; } bool HttpRequest::GetReceiveHeader(HANDLE request_handle, std::string* header) { std::tr1::shared_ptr<HttpInternal>* request = reinterpret_cast<std::tr1::shared_ptr<HttpInternal>*>(request_handle); if (request) { return (*request)->GetHeader(header); } return false; } bool HttpRequest::GetReceiveContent(HANDLE request_handle, std::string* receive) { std::tr1::shared_ptr<HttpInternal>* request = reinterpret_cast<std::tr1::shared_ptr<HttpInternal>*>(request_handle); if (request) { return (*request)->GetContent(receive); } return false; } HttpRequest::HttpInternal::HttpInternal() : m_curl_handle(NULL) , m_perform_thread(NULL) , m_notify(NULL) , m_http_headers(NULL) , m_close_self(false) , m_retry_times(HttpRequest::s_kRetryCount) { m_curl_handle = curl_easy_init(); if (m_curl_handle) { curl_easy_setopt(m_curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); } } HttpRequest::HttpInternal::~HttpInternal() { if (m_curl_handle) { curl_easy_cleanup(m_curl_handle); } if (m_http_headers) { curl_slist_free_all(reinterpret_cast<curl_slist*>(m_http_headers)); } if (m_perform_thread) { CloseHandle(m_perform_thread); } } int HttpRequest::HttpInternal::SetRequestTimeout(long time_out) { if (m_curl_handle) { return curl_easy_setopt(m_curl_handle, CURLOPT_TIMEOUT, 0); } return CURLE_FAILED_INIT; } int HttpRequest::HttpInternal::SetRequestUrl(const std::string& url) { if (m_curl_handle) { return curl_easy_setopt(m_curl_handle, CURLOPT_URL, url.c_str()); } return CURLE_FAILED_INIT; } int HttpRequest::HttpInternal::SetPostMessage(const std::string& message) { if (m_curl_handle) { CURLcode curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_POST, 1); if (curl_code == CURLE_OK) { curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_POSTFIELDS, message.c_str()); } if (curl_code == CURLE_OK) { curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_POSTFIELDSIZE, message.size()); } return curl_code; } return CURLE_FAILED_INIT; } int HttpRequest::HttpInternal::SetHttpHeader(const std::string& header) { if (m_curl_handle) { m_http_headers = curl_slist_append(reinterpret_cast<curl_slist*>(m_http_headers), header.c_str()); return m_http_headers ? CURLE_OK : CURLSHE_BAD_OPTION; } return CURLE_FAILED_INIT; } void HttpRequest::HttpInternal::SetNotify(HttpNotify* notify_object) { m_notify = notify_object; } int HttpRequest::HttpInternal::Perform() { if (m_curl_handle) { CURLcode curl_code; if (m_http_headers) { curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_HTTPHEADER, reinterpret_cast<curl_slist*>(m_http_headers)); if (curl_code != CURLE_OK) { return curl_code; } } receive_header.clear(); receive_content.clear(); curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_HEADERFUNCTION, RequestHelper::RetriveHeaderFunction); curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_HEADERDATA, &receive_header); curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_WRITEFUNCTION, RequestHelper::RetriveContentFunction); curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_WRITEDATA, this); curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_NOPROGRESS, 1); curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_NOSIGNAL, 1); curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_CONNECTTIMEOUT_MS, 0); curl_code = curl_easy_perform(m_curl_handle); if (curl_code == CURLE_OPERATION_TIMEDOUT) { int retry_count = m_retry_times; while (retry_count > 0) { curl_code = curl_easy_perform(m_curl_handle); if (curl_code != CURLE_OPERATION_TIMEDOUT) break; retry_count--; } } curl_easy_getinfo(m_curl_handle, CURLINFO_RESPONSE_CODE, &m_http_code); if (m_http_code == 200) { curl_code = CURLE_OK; if (m_notify) { m_notify->ProcessCallback(HttpNotify::STATE_SUCCESS, 0, ""); m_notify->FinishedNotify(true, receive_content); } } else { const char* err_string = curl_easy_strerror(curl_code); curl_code = CURLE_HTTP_POST_ERROR; if (m_notify) { m_notify->ProcessCallback(HttpNotify::STATE_ERROR, 0, 0); m_notify->FinishedNotify(false, ""); } receive_header.clear(); receive_content.clear(); } return curl_code; } return CURLE_FAILED_INIT; } bool HttpRequest::HttpInternal::GetHeader(std::string* header) { if (receive_header.empty()) return false; else if (header) *header = receive_header; return true; } bool HttpRequest::HttpInternal::GetContent(std::string* receive) { if (receive_content.empty()) return false; else if (receive) *receive = receive_content; return true; }
下面是demo,演示http请求
//demo cpp // http_request.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <Windows.h> #include "HttpRequest.h" #include <iostream> #include <string> #include <fstream> class RequestObject : public HttpNotify { public: virtual void FinishedNotify(bool success, const std::string& content) { if(success) { std::ofstream outfile; outfile.open("baidu.html", std::ios_base::trunc | std::ios_base::binary | std::ios_base::out); if (outfile.good()) { outfile.write(content.c_str(), content.size()); } } } virtual int ProcessCallback(NotifyState state, long size_data, const void* data) { return size_data; } }; int _tmain(int argc, _TCHAR* argv[]) { RequestObject obj; HttpRequest request; request.SetRequestUrl("http://www.baidu.com"); //request.SetPostMessage("hello liyanhong"); request.SetHttpHeader("User-Agent:Mozilla/4.04[en](Win95;I;Nav)"); request.SetNotifyObject(&obj); HANDLE hRequest = request.Perform(HttpRequest::REQUEST_ASYNC); if (hRequest) { Sleep(5000); long http_code; if(request.GetHttpCode(hRequest, &http_code)) std::cout << "http code: " << http_code << std::endl; std::string header; if(request.GetReceiveHeader(hRequest, &header)) { std::cout << header << std::endl; } HttpRequest::Close(hRequest); } return 0; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。