设为首页 收藏本站
查看: 1433|回复: 0

[经验分享] 基于 C++ POCO 库封装的异步多线程的 CHttpClient 类

[复制链接]

尚未签到

发表于 2017-3-1 06:28:50 | 显示全部楼层 |阅读模式
  用惯了 Jetty 的 基于事件的 HttpClient 类,在C++平台上也没找到这样调用方式的类库,只好自己写一个了。
  目前版本 1.0,朋友们看了给点建议。(注:Kylindai原创,转载请注明出处)
  Feature: 基于C++跨平台的 POCO 库实现,支持线程池 Poco::ThreadPool, 异步 HttpClient, 支持Http事件回调处理。
  基本思路,核心方法:
  /**
  * 创建多线程支持的HttpClient,
  * nTimeout 超时
  * nMaxThreads 最大线程数
  * pLogFileName 日志文件
  */
  CHttpClient.Create(int nTimeout, int nMaxThreads, char * pLogFileName = NULL);
  /**
  * 发送请求,此方法会创建一个 CHttpTask 放到线程池里,然后由线程发起 HTTPClientSession 请求,
  * 收到响应后,回调 CHttpExchange.GetHandler().OnResponseComplate() 方法。
  * 类似 Java Jetty的 HttpClient.send(HttpExchange exchange)
  * pExchange CHttpExchange HTTP 交换类
  */
  CHttpClient.Send(CHttpExchange * pExchange);


void CHttpClient::Send(CHttpExchange * pExchange)
{
     try
     {
         CHttpTask * pHttpTask = new CHttpTask(pExchange, m_timeout, m_pLogger);
         ThreadPool::defaultPool().start(* pHttpTask);
     }
     catch (Exception& ex)
     {
         if (m_pLogger != NULL)
         {
             m_pLogger->error(ex.displayText());
         }
     }
}  /**
  * 线程池中任务 CHttpTask.run 处理Http请求及响应
  */
  CHttpTask : public Runnable


void CHttpTask::run()
{
     CHttpHandler * pHandler = m_pExchange->GetHandler();

     try
     {
         HTTPClientSession httpClientSession;
         httpClientSession.setHost(m_pExchange->GetHost());
         httpClientSession.setTimeout(m_timeout);
         httpClientSession.sendRequest(m_pExchange->GetHttpRequest());

         HTTPResponse response;
         istream& rs = httpClientSession.receiveResponse(response);

         if (pHandler != NULL)
         {
             const string& contentType = response.getContentType();
             if (contentType.find("text/") >= 0)
             {
                 stringstream responseStream;
                 StreamCopier::copyStream(rs, responseStream);

                 string responseContent;
                 responseStream >> responseContent;

                 pHandler->OnResponseComplete(response.getStatus(), responseContent);
             }
         }
     }
     catch (Exception& ex)
     {
         if (m_pLogger != NULL)
         {
             m_pLogger->error(ex.displayText());
         }
     }

     if (pHandler != NULL)
     {
         delete pHandler;
     }

     delete this;
}  /**
  * 为HttpExchange 设置 Handler 处理回调类,以后具体的逻辑由 CHttpHandler 继承的具体业务处理逻辑类完成。
  * pHandler CHttpHandler HTTP 事件处理类
  */
  CHttpExchange.SetHandler(CHttpHandler * pHandler);
  /**
  * 当收到响应完成时的事件回调函数,传入 HttpStatus 和 文本的Response,
  * 目前仅支持文本 Response,即:Resonse.getContentType() 为 text 类型
  */
  CHttpHandler.OnResponseComplate(HTTPResponse::HTTPStatus status, const string& responseContent);
  CCheckVersionHandler : public CHttpHandler


void CCheckVersionHandler::OnResponseComplete(HTTPResponse::HTTPStatus status, const string& responseContent)
{
     CHttpHandler::OnResponseComplete(status, responseContent);

     if (status == HTTPResponse::HTTP_OK)
     {
         const string& version = responseContent;

         m_pMainWnd->ShowVersionMessage(version);
     }
}  (一)CHttpClient CHttpExchange CHttpHandler 类图:
  (二)代码:
  HttpClient.h


//////////////////////////////////////////////////////////////////////////
//  HttpClient.h
//  Author: Kylin.dai @kylindai
//  Date: 2011-05-21
//////////////////////////////////////////////////////////////////////////

#pragma once

#include "Poco/AutoPtr.h"
#include "Poco/Logger.h"
#include "Poco/PatternFormatter.h"
#include "Poco/FormattingChannel.h"
#include "Poco/ConsoleChannel.h"
#include "Poco/FileChannel.h"
#include "Poco/Message.h"
#include "Poco/Exception.h"
#include "Poco/StreamCopier.h"
#include "Poco/ThreadPool.h"
#include "Poco/Thread.h"
#include "Poco/Mutex.h"
#include "Poco/Runnable.h"
#include "Poco/Stopwatch.h"
#include "Poco/Net/HTTPClientSession.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"

#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <map>

using namespace std;
using namespace Poco;
using namespace Poco::Net;

//////////////////////////////////////////////////////////////////////////
// CHttpHandler Class
//////////////////////////////////////////////////////////////////////////
class CHttpHandler
{
public:
     CHttpHandler(char * pLogFileName = NULL);
     ~CHttpHandler();

private:
     map<const string, LPVOID> m_attributeMap;

protected:
     Logger * m_pLogger;

public:
     void SetAttribute(const string& name, LPVOID value);
     LPVOID GetAttribute(const string& name);

     virtual void OnException();
     virtual void OnExpire();
     virtual void OnRequestComplete();
     virtual void OnResponseComplete(HTTPResponse::HTTPStatus status, const string& responseContent);
};

//////////////////////////////////////////////////////////////////////////
// CHttpExchange Class
//////////////////////////////////////////////////////////////////////////
class CHttpExchange
{
public:
     CHttpExchange();
     ~CHttpExchange();

private:
     int m_timeout;
     HTTPRequest * m_pRequest;
     CHttpHandler * m_pHandler;

public:
     HTTPRequest& GetHttpRequest();

     void SetMethod(const string& strMethod);
     const string& GetMethod() const;

     void SetContentType(const string& strContentType);
     const string& GetContentType() const;

     void SetHost(const string& strHost);
     const string& GetHost() const;

     void SetUri(const string& strUri);
     const string& GetUri() const;

     void SetHandler(CHttpHandler * pHandler);
     CHttpHandler * GetHandler();
};

//////////////////////////////////////////////////////////////////////////
// CHttpTask Class
//////////////////////////////////////////////////////////////////////////
class CHttpTask : public Runnable
{
public:
     CHttpTask(CHttpExchange * pExchange, int timeout = 15000, Logger * pLogger = NULL);
     ~CHttpTask();

private:
     CHttpExchange * m_pExchange;
     int m_timeout;

protected:
     Logger * m_pLogger;

public:
     void run();
};

//////////////////////////////////////////////////////////////////////////
// CHttpClient Class
//////////////////////////////////////////////////////////////////////////
class CHttpClient
{
public:
     CHttpClient();
     ~CHttpClient();

private:
     int m_timeout;
     int m_threads;
     char * m_pLogFileName;

protected:
     Logger * m_pLogger;

public:
     void Create(int timeout = 15000, int threads = 20, char * pLogFileName = NULL);
     void Start();
     void Stop();
     void Send(CHttpExchange * pExchange);
};  HttpClient.cpp


//////////////////////////////////////////////////////////////////////////
//  HttpClient.cpp
//  Author: Kylin.dai @kylindai
//  Date: 2011-05-21
//////////////////////////////////////////////////////////////////////////

#include "HttpClient.h"

//////////////////////////////////////////////////////////////////////////
// CHttpHandler Methods
//////////////////////////////////////////////////////////////////////////
CHttpHandler::CHttpHandler(char * pLogFileName)
{
     m_pLogger = NULL;

     // create logger
     if (pLogFileName != NULL)
     {
         try
         {
             string logFileName(pLogFileName);

             FormattingChannel* pFCFile = new FormattingChannel(new PatternFormatter("%Y-%m-%d %H:%M:%S.%c %N[%P]:%s:%q:%t"));
             pFCFile->setChannel(new FileChannel(logFileName));
             pFCFile->open();

             m_pLogger = & Logger::create("HttpHandler", pFCFile, Message::PRIO_DEBUG); //Message::PRIO_WARNING);
         }
         catch (Exception& ex)
         {
         }
     }
}

CHttpHandler::~CHttpHandler()
{
     if (m_pLogger != NULL)
     {
         m_pLogger->getChannel()->close();
     }
}

void CHttpHandler::SetAttribute(const string& name, LPVOID value)
{
     m_attributeMap[name] = value;
}

LPVOID CHttpHandler::GetAttribute(const string& name)
{
     return m_attributeMap[name];
}

void CHttpHandler::OnException()
{

}

void CHttpHandler::OnExpire()
{

}

void CHttpHandler::OnRequestComplete()
{

}

void CHttpHandler::OnResponseComplete(HTTPResponse::HTTPStatus status, const string& responseContent)
{
     if (m_pLogger != NULL)
     {
         stringstream messageStream;
         messageStream << "HTTP STATUS:" << status << " : " << responseContent << endl;

         m_pLogger->debug(messageStream.str());
     }
}

//////////////////////////////////////////////////////////////////////////
// CHttpExchange Methods
//////////////////////////////////////////////////////////////////////////
CHttpExchange::CHttpExchange()
{
     m_pRequest = new HTTPRequest();
     m_pRequest->setVersion(HTTPRequest::HTTP_1_1);
}

CHttpExchange::~CHttpExchange()
{
     if (m_pRequest != NULL)
     {
//        delete m_pRequest;
     }
}

HTTPRequest& CHttpExchange::GetHttpRequest()
{
     return * m_pRequest;
}

void CHttpExchange::SetMethod(const string& strMethod)
{
     m_pRequest->setMethod(strMethod);
}

const string& CHttpExchange::GetMethod() const
{
     return m_pRequest->getMethod();
}

void CHttpExchange::SetContentType(const string& strContentType)
{
     m_pRequest->setContentType(strContentType);
}

const string& CHttpExchange::GetContentType() const
{
     return m_pRequest->getContentType();
}

void CHttpExchange::SetHost(const string& strHost)
{
     m_pRequest->setHost(strHost);
}

const string& CHttpExchange::GetHost() const
{
     return m_pRequest->getHost();
}

void CHttpExchange::SetUri(const string& strUri)
{
     m_pRequest->setURI(strUri);
}

const string& CHttpExchange::GetUri() const
{
     return m_pRequest->getURI();
}

void CHttpExchange::SetHandler(CHttpHandler * pHandler)
{
     m_pHandler = pHandler;
}

CHttpHandler * CHttpExchange::GetHandler()
{
     return m_pHandler;
}

//////////////////////////////////////////////////////////////////////////
// CHttpTask Methods
//////////////////////////////////////////////////////////////////////////
CHttpTask::CHttpTask(CHttpExchange * pExchange, int timeout, Logger * pLogger):
     m_pExchange(pExchange),
     m_timeout(timeout),
     m_pLogger(pLogger)
{
     
}

CHttpTask::~CHttpTask()
{
     if (m_pExchange != NULL)
     {
         delete m_pExchange;
     }
}

void CHttpTask::run()
{
     CHttpHandler * pHandler = m_pExchange->GetHandler();

     try
     {
         HTTPClientSession httpClientSession;
         httpClientSession.setHost(m_pExchange->GetHost());
         httpClientSession.setTimeout(m_timeout);
         httpClientSession.sendRequest(m_pExchange->GetHttpRequest());

         HTTPResponse response;
         istream& rs = httpClientSession.receiveResponse(response);

         if (pHandler != NULL)
         {
             const string& contentType = response.getContentType();
             if (contentType.find("text/") >= 0)
             {
                 stringstream responseStream;
                 StreamCopier::copyStream(rs, responseStream);

                 string responseContent;
                 responseStream >> responseContent;

                 pHandler->OnResponseComplete(response.getStatus(), responseContent);
             }
         }
     }
     catch (Exception& ex)
     {
         if (m_pLogger != NULL)
         {
             m_pLogger->error(ex.displayText());
         }
     }

     if (pHandler != NULL)
     {
         delete pHandler;
     }

     delete this;
}

//////////////////////////////////////////////////////////////////////////
// CHttpClient Methods
//////////////////////////////////////////////////////////////////////////
CHttpClient::CHttpClient()
{
     m_pLogger = NULL;
}

CHttpClient::~CHttpClient()
{
     if (m_pLogger != NULL)
     {
         m_pLogger->getChannel()->close();
     }
}

void CHttpClient::Create(int timeout, int threads, char * pLogFileName)
{
     m_timeout = timeout;
     m_threads = threads;
     m_pLogFileName = pLogFileName;

     ThreadPool::defaultPool().addCapacity(threads);

     // create logger
     if (pLogFileName != NULL)
     {
         try
         {
             string logFileName(pLogFileName);

             FormattingChannel* pFCFile = new FormattingChannel(new PatternFormatter("%Y-%m-%d %H:%M:%S.%c %N[%P]:%s:%q:%t"));
             pFCFile->setChannel(new FileChannel(logFileName));
             pFCFile->open();

             m_pLogger = & Logger::create("fileLogger", pFCFile, Message::PRIO_WARNING);
         }
         catch (Exception& ex)
         {
         }
     }
     /*
     else
     {
         FormattingChannel* pFCConsole = new FormattingChannel(new PatternFormatter("%s: %p: %t"));
         pFCConsole->setChannel(new ConsoleChannel);
         pFCConsole->open();

         m_pLogger = & Logger::create("ConsoleLogger", pFCConsole, Message::PRIO_DEBUG);
     }
     */
}

void CHttpClient::Start()
{

}

void CHttpClient::Stop()
{
//    ThreadPool::defaultPool().joinAll();
}

void CHttpClient::Send(CHttpExchange * pExchange)
{
     try
     {
         CHttpTask * pHttpTask = new CHttpTask(pExchange, m_timeout, m_pLogger);
         ThreadPool::defaultPool().start(* pHttpTask);
     }
     catch (Exception& ex)
     {
         if (m_pLogger != NULL)
         {
             m_pLogger->error(ex.displayText());
         }
     }
}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-348476-1-1.html 上篇帖子: 基于WEB 的实时事件通知方案 下篇帖子: 在eclipse中运行cassandra
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表