基于 C++ POCO 库封装的异步多线程的 CHttpClient 类

用惯了 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); 

 1 void CHttpClient::Send(CHttpExchange * pExchange)
 2 {
 3     try 
 4     {
 5         CHttpTask * pHttpTask = new CHttpTask(pExchange, m_timeout, m_pLogger);
 6         ThreadPool::defaultPool().start(* pHttpTask);
 7     } 
 8     catch (Exception& ex)
 9     {
10         if (m_pLogger != NULL)
11         {
12             m_pLogger->error(ex.displayText());
13         }
14     }
15 }

/**

 * 线程池中任务 CHttpTask.run 处理Http请求及响应

 */

CHttpTask : public Runnable

 1 void CHttpTask::run()
 2 {
 3     CHttpHandler * pHandler = m_pExchange->GetHandler();
 4 
 5     try
 6     {
 7         HTTPClientSession httpClientSession;
 8         httpClientSession.setHost(m_pExchange->GetHost());
 9         httpClientSession.setTimeout(m_timeout);
10         httpClientSession.sendRequest(m_pExchange->GetHttpRequest());
11 
12         HTTPResponse response;
13         istream& rs = httpClientSession.receiveResponse(response);
14 
15         if (pHandler != NULL)
16         {
17             const string& contentType = response.getContentType();
18             if (contentType.find("text/">= 0)
19             {
20                 stringstream responseStream;
21                 StreamCopier::copyStream(rs, responseStream);
22 
23                 string responseContent;
24                 responseStream >> responseContent;
25 
26                 pHandler->OnResponseComplete(response.getStatus(), responseContent);
27             }
28         }
29     }
30     catch (Exception& ex)
31     {
32         if (m_pLogger != NULL)
33         {
34             m_pLogger->error(ex.displayText());
35         }
36     }
37 
38     if (pHandler != NULL)
39     {
40         delete pHandler;
41     }
42 
43     delete this;
44 }

/**

 * 为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

 1 void CCheckVersionHandler::OnResponseComplete(HTTPResponse::HTTPStatus status, const string& responseContent)
 2 {
 3     CHttpHandler::OnResponseComplete(status, responseContent);
 4 
 5     if (status == HTTPResponse::HTTP_OK)
 6     {
 7         const string& version = responseContent;
 8 
 9         m_pMainWnd->ShowVersionMessage(version);
10     }
11 }

(一)CHttpClient CHttpExchange CHttpHandler 类图:

(二)代码:

HttpClient.h

  1 //////////////////////////////////////////////////////////////////////////
  2 //  HttpClient.h
  3 //  Author: Kylin.dai @kylindai
  4 //  Date: 2011-05-21
  5 //////////////////////////////////////////////////////////////////////////
  6 
  7 #pragma once
  8 
  9 #include "Poco/AutoPtr.h"
 10 #include "Poco/Logger.h"
 11 #include "Poco/PatternFormatter.h"
 12 #include "Poco/FormattingChannel.h"
 13 #include "Poco/ConsoleChannel.h"
 14 #include "Poco/FileChannel.h"
 15 #include "Poco/Message.h"
 16 #include "Poco/Exception.h"
 17 #include "Poco/StreamCopier.h"
 18 #include "Poco/ThreadPool.h"
 19 #include "Poco/Thread.h"
 20 #include "Poco/Mutex.h"
 21 #include "Poco/Runnable.h"
 22 #include "Poco/Stopwatch.h"
 23 #include "Poco/Net/HTTPClientSession.h"
 24 #include "Poco/Net/HTTPRequest.h"
 25 #include "Poco/Net/HTTPResponse.h"
 26 
 27 #include <string>
 28 #include <iostream>
 29 #include <sstream>
 30 #include <fstream>
 31 #include <map>
 32 
 33 using namespace std;
 34 using namespace Poco;
 35 using namespace Poco::Net;
 36 
 37 //////////////////////////////////////////////////////////////////////////
 38 // CHttpHandler Class
 39 //////////////////////////////////////////////////////////////////////////
 40 class CHttpHandler
 41 {
 42 public:
 43     CHttpHandler(char * pLogFileName = NULL);
 44     ~CHttpHandler();
 45 
 46 private:
 47     map<const string, LPVOID> m_attributeMap;
 48 
 49 protected:
 50     Logger * m_pLogger;
 51 
 52 public:
 53     void SetAttribute(const string& name, LPVOID value);
 54     LPVOID GetAttribute(const string& name);
 55 
 56     virtual void OnException();
 57     virtual void OnExpire();
 58     virtual void OnRequestComplete();
 59     virtual void OnResponseComplete(HTTPResponse::HTTPStatus status, const string& responseContent);
 60 };
 61 
 62 //////////////////////////////////////////////////////////////////////////
 63 // CHttpExchange Class
 64 //////////////////////////////////////////////////////////////////////////
 65 class CHttpExchange
 66 {
 67 public:
 68     CHttpExchange();
 69     ~CHttpExchange();
 70 
 71 private:
 72     int m_timeout;
 73     HTTPRequest * m_pRequest;
 74     CHttpHandler * m_pHandler;
 75 
 76 public:
 77     HTTPRequest& GetHttpRequest();
 78 
 79     void SetMethod(const string& strMethod);
 80     const string& GetMethod() const;
 81 
 82     void SetContentType(const string& strContentType);
 83     const string& GetContentType() const;
 84 
 85     void SetHost(const string& strHost);
 86     const string& GetHost() const;
 87 
 88     void SetUri(const string& strUri);
 89     const string& GetUri() const;
 90 
 91     void SetHandler(CHttpHandler * pHandler);
 92     CHttpHandler * GetHandler();
 93 };
 94 
 95 //////////////////////////////////////////////////////////////////////////
 96 // CHttpTask Class
 97 //////////////////////////////////////////////////////////////////////////
 98 class CHttpTask : public Runnable
 99 {
100 public:
101     CHttpTask(CHttpExchange * pExchange, int timeout = 15000, Logger * pLogger = NULL);
102     ~CHttpTask();
103 
104 private:
105     CHttpExchange * m_pExchange;
106     int m_timeout;
107 
108 protected:
109     Logger * m_pLogger;
110 
111 public:
112     void run();
113 };
114 
115 //////////////////////////////////////////////////////////////////////////
116 // CHttpClient Class
117 //////////////////////////////////////////////////////////////////////////
118 class CHttpClient
119 {
120 public:
121     CHttpClient();
122     ~CHttpClient();
123 
124 private:
125     int m_timeout;
126     int m_threads;
127     char * m_pLogFileName;
128 
129 protected:
130     Logger * m_pLogger;
131 
132 public:
133     void Create(int timeout = 15000int threads = 20char * pLogFileName = NULL);
134     void Start();
135     void Stop();
136     void Send(CHttpExchange * pExchange);
137 };

HttpClient.cpp

  1 //////////////////////////////////////////////////////////////////////////
  2 //  HttpClient.cpp
  3 //  Author: Kylin.dai @kylindai
  4 //  Date: 2011-05-21
  5 //////////////////////////////////////////////////////////////////////////
  6 
  7 #include "HttpClient.h"
  8 
  9 //////////////////////////////////////////////////////////////////////////
 10 // CHttpHandler Methods
 11 //////////////////////////////////////////////////////////////////////////
 12 CHttpHandler::CHttpHandler(char * pLogFileName)
 13 {
 14     m_pLogger = NULL;
 15 
 16     // create logger
 17     if (pLogFileName != NULL) 
 18     {
 19         try
 20         {
 21             string logFileName(pLogFileName);
 22 
 23             FormattingChannel* pFCFile = new FormattingChannel(new PatternFormatter("%Y-%m-%d %H:%M:%S.%c %N[%P]:%s:%q:%t"));
 24             pFCFile->setChannel(new FileChannel(logFileName));
 25             pFCFile->open();
 26 
 27             m_pLogger = & Logger::create("HttpHandler", pFCFile, Message::PRIO_DEBUG); //Message::PRIO_WARNING);
 28         }
 29         catch (Exception& ex)
 30         {
 31         }
 32     } 
 33 }
 34 
 35 CHttpHandler::~CHttpHandler()
 36 {
 37     if (m_pLogger != NULL)
 38     {
 39         m_pLogger->getChannel()->close();
 40     }
 41 }
 42 
 43 void CHttpHandler::SetAttribute(const string& name, LPVOID value)
 44 {
 45     m_attributeMap[name] = value;
 46 }
 47 
 48 LPVOID CHttpHandler::GetAttribute(const string& name)
 49 {
 50     return m_attributeMap[name];
 51 }
 52 
 53 void CHttpHandler::OnException()
 54 {
 55 
 56 }
 57 
 58 void CHttpHandler::OnExpire()
 59 {
 60 
 61 }
 62 
 63 void CHttpHandler::OnRequestComplete()
 64 {
 65 
 66 }
 67 
 68 void CHttpHandler::OnResponseComplete(HTTPResponse::HTTPStatus status, const string& responseContent)
 69 {
 70     if (m_pLogger != NULL)
 71     {
 72         stringstream messageStream;
 73         messageStream << "HTTP STATUS:" << status << " : " << responseContent << endl;
 74 
 75         m_pLogger->debug(messageStream.str());
 76     }
 77 }
 78 
 79 //////////////////////////////////////////////////////////////////////////
 80 // CHttpExchange Methods
 81 //////////////////////////////////////////////////////////////////////////
 82 CHttpExchange::CHttpExchange() 
 83 {
 84     m_pRequest = new HTTPRequest();
 85     m_pRequest->setVersion(HTTPRequest::HTTP_1_1);
 86 }
 87 
 88 CHttpExchange::~CHttpExchange()
 89 {
 90     if (m_pRequest != NULL)
 91     {
 92 //        delete m_pRequest;
 93     }
 94 }
 95 
 96 HTTPRequest& CHttpExchange::GetHttpRequest()
 97 {
 98     return * m_pRequest;
 99 }
100 
101 void CHttpExchange::SetMethod(const string& strMethod)
102 {
103     m_pRequest->setMethod(strMethod);
104 }
105 
106 const string& CHttpExchange::GetMethod() const
107 {
108     return m_pRequest->getMethod();
109 }
110 
111 void CHttpExchange::SetContentType(const string& strContentType)
112 {
113     m_pRequest->setContentType(strContentType);
114 }
115 
116 const string& CHttpExchange::GetContentType() const
117 {
118     return m_pRequest->getContentType();
119 }
120 
121 void CHttpExchange::SetHost(const string& strHost)
122 {
123     m_pRequest->setHost(strHost);
124 }
125 
126 const string& CHttpExchange::GetHost() const
127 {
128     return m_pRequest->getHost();
129 }
130 
131 void CHttpExchange::SetUri(const string& strUri)
132 {
133     m_pRequest->setURI(strUri);
134 }
135 
136 const string& CHttpExchange::GetUri() const
137 {
138     return m_pRequest->getURI();
139 }
140 
141 void CHttpExchange::SetHandler(CHttpHandler * pHandler)
142 {
143     m_pHandler = pHandler;
144 }
145 
146 CHttpHandler * CHttpExchange::GetHandler()
147 {
148     return m_pHandler;
149 }
150 
151 //////////////////////////////////////////////////////////////////////////
152 // CHttpTask Methods
153 //////////////////////////////////////////////////////////////////////////
154 CHttpTask::CHttpTask(CHttpExchange * pExchange, int timeout, Logger * pLogger):
155     m_pExchange(pExchange),
156     m_timeout(timeout),
157     m_pLogger(pLogger)
158 {
159     
160 }
161 
162 CHttpTask::~CHttpTask()
163 {
164     if (m_pExchange != NULL)
165     {
166         delete m_pExchange;
167     }
168 }
169 
170 void CHttpTask::run()
171 {
172     CHttpHandler * pHandler = m_pExchange->GetHandler();
173 
174     try
175     {
176         HTTPClientSession httpClientSession;
177         httpClientSession.setHost(m_pExchange->GetHost());
178         httpClientSession.setTimeout(m_timeout);
179         httpClientSession.sendRequest(m_pExchange->GetHttpRequest());
180 
181         HTTPResponse response;
182         istream& rs = httpClientSession.receiveResponse(response);
183 
184         if (pHandler != NULL)
185         {
186             const string& contentType = response.getContentType();
187             if (contentType.find("text/">= 0)
188             {
189                 stringstream responseStream;
190                 StreamCopier::copyStream(rs, responseStream);
191 
192                 string responseContent;
193                 responseStream >> responseContent;
194 
195                 pHandler->OnResponseComplete(response.getStatus(), responseContent);
196             }
197         }
198     }
199     catch (Exception& ex)
200     {
201         if (m_pLogger != NULL)
202         {
203             m_pLogger->error(ex.displayText());
204         }
205     }
206 
207     if (pHandler != NULL)
208     {
209         delete pHandler;
210     }
211 
212     delete this;
213 }
214 
215 //////////////////////////////////////////////////////////////////////////
216 // CHttpClient Methods
217 //////////////////////////////////////////////////////////////////////////
218 CHttpClient::CHttpClient()
219 {
220     m_pLogger = NULL;
221 }
222 
223 CHttpClient::~CHttpClient()
224 {
225     if (m_pLogger != NULL)
226     {
227         m_pLogger->getChannel()->close();
228     }
229 }
230 
231 void CHttpClient::Create(int timeout, int threads, char * pLogFileName)
232 {
233     m_timeout = timeout;
234     m_threads = threads;
235     m_pLogFileName = pLogFileName;
236 
237     ThreadPool::defaultPool().addCapacity(threads);
238 
239     // create logger
240     if (pLogFileName != NULL) 
241     {
242         try
243         {
244             string logFileName(pLogFileName);
245 
246             FormattingChannel* pFCFile = new FormattingChannel(new PatternFormatter("%Y-%m-%d %H:%M:%S.%c %N[%P]:%s:%q:%t"));
247             pFCFile->setChannel(new FileChannel(logFileName));
248             pFCFile->open();
249 
250             m_pLogger = & Logger::create("fileLogger", pFCFile, Message::PRIO_WARNING);
251         }
252         catch (Exception& ex)
253         {
254         }
255     } 
256     /*
257     else 
258     {
259         FormattingChannel* pFCConsole = new FormattingChannel(new PatternFormatter("%s: %p: %t"));
260         pFCConsole->setChannel(new ConsoleChannel);
261         pFCConsole->open();
262 
263         m_pLogger = & Logger::create("ConsoleLogger", pFCConsole, Message::PRIO_DEBUG);
264     }
265     */
266 }
267 
268 void CHttpClient::Start()
269 {
270 
271 }
272 
273 void CHttpClient::Stop()
274 {
275 //    ThreadPool::defaultPool().joinAll();
276 }
277 
278 void CHttpClient::Send(CHttpExchange * pExchange)
279 {
280     try 
281     {
282         CHttpTask * pHttpTask = new CHttpTask(pExchange, m_timeout, m_pLogger);
283         ThreadPool::defaultPool().start(* pHttpTask);
284     } 
285     catch (Exception& ex)
286     {
287         if (m_pLogger != NULL)
288         {
289             m_pLogger->error(ex.displayText());
290         }
291     }
292 }
原文地址:https://www.cnblogs.com/kylindai/p/2053173.html