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;
}
时间: 2024-10-14 13:12:28

libcurl的封装,支持同步请求,支持异步通知请求的相关文章

《Linux4.0设备驱动开发详解》笔记--第九章:Linux设备驱动中的异步通知与同步I/O

在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问.因此,使用无阻塞I/O的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似"中断"的异步通知所取代.异步通知类似于硬件上的"中断"概念,比较准确的称谓是"信号驱动的异步I/O". 9.1 异步通知的概念和作用 异步通知:一旦设备就绪,则主动通知应用程序,该应用程序无需查询设备状态 几种通知方式比较: 阻塞I/O :一直等待设备可访问后开始访问 非阻塞I/O:

Hasen的linux设备驱动开发学习之旅--异步通知

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:异步通知 * Date:2014-11-05 */ 一.异步通知的概念和作用 阻塞和非阻塞访问.poll()函数提供了较好地解决设备访问的机制,但是如果有了异步通知整套机制就更 加完整了. 异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这 一点非常类似于硬件上"中断"的概

Smart20学习记录----异步通知

异步通知: 阻塞与非阻塞访问.poll()函数提供了较好地解决设备访问的机制(应用程序主动访问) 异步通知:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步 I/O” 阻塞 I/O 意味着一直等待设备可访问后再访问,非阻塞 I/O 中使用 poll()意味着查询设备是否可访问,而异步通知则意味着设备通知自身可访问,实现了异步 I/O.由此可见,这几种方式 I/O可以互为补充. 阻塞.非阻塞 I/O.异步

【Java&amp;Android开源库代码剖析】のandroid-async-http(如何设计一个优雅的Android网络请求框架,同时支持同步和异步请求)开篇

在<[Java&Android开源库代码剖析]のandroid-smart-image-view>一文中我们提到了android-async-http这个开源库,本文正式开篇来详细介绍这个库的实现,同时结合源码探讨如何设计一个优雅的Android网络请求框架.做过一段时间Android开发的同学应该对这个库不陌生,因为它对Apache的HttpClient API的封装使得开发者可以简洁优雅的实现网络请求和响应,并且同时支持同步和异步请求. 网络请求框架一般至少需要具备如下几个组件:1

ANTS Performance Profiler 8:支持对Web请求、异步代码和WinRT的性能剖析

下载与激活:http://download.csdn.net/detail/lone112/6734291 离线激活 位于英国的Red Gate Software有限公司最近发布了ANTS Performance Profiler 8 Beta,支持对Web请求.异步代码和Windows商店应用的性能剖析.该版本还支持SharePoint 2013和一个新的时间线,这使开发者不但能够监控应用程序的性能,还能深入到想要检查的具体区域. Web请求剖析使开发者能够捕获向外的HTTP请求,其中包括请求

javascript 异步请求封装成同步请求

此方法是异步请求封装成同步请求,加上token验证,环境试用微信小程序,可以修改文件中的ajax,进行封装自己的,比如用axios等 成功码采用标准的 200 到 300 和304 ,需要可以自行修改 同步任务接入之后,每个任务会进行token的验证,每个任务之间都是同步请求,包括token /** * 同步流请求 * token验证每个接口 * 柯里化添加同步任务 * resolve返回res,cb * reject 返回res,cb * 通过任务中断测试 * 通过成功失败回调函数测试 * *

AJAX的来龙去脉(由来)-如果被封装出来的--ajax发送异步请求(四步操作)

<黑马程序员_超全面的JavaWeb视频教程vedio\JavaWeb视频教程_day23_ajax> \JavaWeb视频教程_day23_ajax\day23ajax_avi\14.打包ajax生成小工具.avi;  有介绍: 个人理解:就是封装了 XMLHttpRequest 的请求方法:演变而成我们常用的 ajax: =====原始的请求方式: ajax发送异步请求(四步操作) 1. 第一步(得到XMLHttpRequest) * ajax其实只需要学习一个对象:XMLHttpRequ

POST和GET以及同步请求和异步请求的区别

一.HTTP是应用层的网络传输协议,对于HTTP的请求方式主要流行的GET请求与POST请求对于GET请求与POST请求的区别 1.GET请求,服务器以及参数都会出现在请求接口中,也就是请求参数也是接口的一部分,而POST请求在接口中只有服务器地址,而参数会作为请求提交给服务器. 2.因为GET请求会出现在请求接口中,所以信息容易被捕获,安全性低,POST请求参数封装在请求体中,作为二进制流进行传输,不易被捕获,安全性高. 3.GET在请求时,接口的字节数有限制,支持小数据的提交,而POST请求

ajax,同步请求 ,异步请求

同步请求,异步请求 ,这样的字眼我想既然你能看到这篇文章并且点击进来 ,说明我们应该是听过他的,并且 听得次数还不少,说到异步请求 ,首先我想到就是ajax, ajax的问题一会再说,今天我突然想到,我们平时都会 尽量的去 用ajax使用异步 的方式请求数据, 那么你知道到底是同步请求的数据更快,还是异步请求的数据更快吗? 异步传输是面向字符的传输,它的单位是字符:而同步传输是面向比特的传输,它的单位是桢,它传输的时候要求接受方和发送方的时钟是保持一致的. 同步传输通常要比异步传输快速得多.接收