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

时间:2021-05-13 18:06:48

用惯了 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  =   15000 int  threads  =   20 char   *  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  }