用惯了 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
}