经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
利用gsoap库封装易用的rest框架
来源:cnblogs  作者:lijianbo  时间:2018/11/25 20:04:57  对本文有异议

c++缺少web开发的框架,web框架分为异步和同步,异步的业务逻辑控制需要较强功底,同步代码实现起来容易,利于阅读理解

 

1.gsoap是c++写的webservice库,webservice应用层也是用http进行传输的,gsoap提供了httpget和httppost的插件,本文对这两个插件进行改造,可以支持restful风格的接口。下面是的代码需要在c++11支持的编译器下运行,rest包装的内容用json传递

2.利于gsoap的soapcpp2.exe工具生成env文件

命令

mkdir env

soapcpp2.exe -penv -denv env.h

3.拷贝源码目录下的stdsoap2.h和stdsoap2.cpp,和http插件包含进你的工程

4.server文件

  1. 1 #ifndef SoapWebServer_279437A4_6013_4E56_B152_EC3D528A0CC2_H__
  2. 2 #define SoapWebServer_279437A4_6013_4E56_B152_EC3D528A0CC2_H__
  3. 3
  4. 4 #include <string>
  5. 5 #include <map>
  6. 6 #include <list>
  7. 7 #include <queue>
  8. 8 #include <mutex>
  9. 9 #include <condition_variable>
  10. 10 #include <thread>
  11. 11
  12. 12 using namespace std;
  13. 13 #include "stdsoap2.h"
  14. 14 #include "RestServicePlugin.h"
  15. 15 using namespace Http;
  16. 16
  17. 17 class CSoapWebServer
  18. 18 {
  19. 19 public:
  20. 20 CSoapWebServer();
  21. 21 ~CSoapWebServer();
  22. 22
  23. 23 static const int AcceptTimeout = 3;//>单位s
  24. 24 static const int RecvTimeout = 30;//>单位s
  25. 25 static const int SendTimeout = 30;//>单位s
  26. 26 static const int MaxThreadCount = 8;
  27. 27 static const unsigned int WaitTimeout = 1000; //>单位s
  28. 28 void SetURI(const char* URI,RequestProcessFunc fun, void * user);
  29. 29 void SetURI(const char* URI, RequestProcessFunction & fun);
  30. 30 void ResetURI(const char* URI);
  31. 31 void ClearURI();
  32. 32
  33. 33 bool StartService(const char* ip,unsigned int port);
  34. 34 void StopService();
  35. 35
  36. 36 protected:
  37. 37 struct THREAD_INFO
  38. 38 {
  39. 39 struct soap* soap_listen;
  40. 40 struct soap* soap_client;
  41. 41 CSoapWebServer* pThis;
  42. 42 };
  43. 43 bool StartThread();
  44. 44 void CloseThread();
  45. 45
  46. 46 void ServiceListenThread();
  47. 47 void ServiceServeThread(THREAD_INFO*pParam);
  48. 48 void Listen();
  49. 49 void ExecuteServe(THREAD_INFO* info);
  50. 50 int SoapServ(struct soap* soap);
  51. 51
  52. 52 int BeginServe(struct soap* soap);
  53. 53 int EndServe(struct soap* soap);
  54. 54
  55. 55 struct soap* PopSoap(void);
  56. 56 void PushSoap(struct soap* soap);
  57. 57 void FreeSoapAll(void);
  58. 58 private:
  59. 59
  60. 60 CRestServicePlugin m_service;
  61. 61 struct soap* m_pSoap;
  62. 62 volatile bool m_bExit;
  63. 63 std::thread *m_ListenThread; //>接收线程句柄
  64. 64 std::thread *m_ServeThread[MaxThreadCount]; //>服务执行线程
  65. 65 struct CLIENT_INFO
  66. 66 {
  67. 67 SOAP_SOCKET socket;
  68. 68 unsigned long ip;
  69. 69 unsigned int port;
  70. 70 };
  71. 71 std::queue<CLIENT_INFO> m_acceptClientList;
  72. 72 std::queue<struct soap*> m_soapList;
  73. 73 std::mutex m_listMt;
  74. 74 std::condition_variable m_cvClient;
  75. 75 unsigned int m_iClientCount;
  76. 76 };
  77. 77
  78. 78 #endif // SoapWebServer_279437A4_6013_4E56_B152_EC3D528A0CC2_H__
View Code
  1. 5.server.cpp文件
  1. 1 #include "SoapWebServer.h"
  2. 2 //#include "soap.nsmap"
  3. 3
  4. 4 SOAP_NMAC struct Namespace namespaces[] = {
  5. 5 {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},
  6. 6 {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL},
  7. 7 {"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},
  8. 8 {"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL},
  9. 9 {NULL, NULL, NULL, NULL}
  10. 10 };
  11. 11
  12. 12 int TestAPI(Request& request)
  13. 13 {
  14. 14 char* body = NULL;
  15. 15 size_t body_len = request.GetBody(&body);
  16. 16
  17. 17 Response res(request);
  18. 18 res.SetContentType("text/json");
  19. 19 res.Send("{\"name\":\"bobo\",\"age\": 50}");
  20. 20
  21. 21 return SOAP_OK;
  22. 22 }
  23. 23
  24. 24 CSoapWebServer::CSoapWebServer():
  25. 25 m_pSoap(NULL),
  26. 26 m_bExit(false),
  27. 27 m_ListenThread(nullptr),
  28. 28 m_iClientCount(0)
  29. 29 {
  30. 30 for (int i = 0; i < MaxThreadCount; ++i)
  31. 31 {
  32. 32 m_ServeThread[i] = nullptr;
  33. 33 }
  34. 34 }
  35. 35
  36. 36 CSoapWebServer::~CSoapWebServer()
  37. 37 {
  38. 38
  39. 39 }
  40. 40 void CSoapWebServer::ClearURI()
  41. 41 {
  42. 42 m_service.ClearURI();
  43. 43 }
  44. 44
  45. 45 void CSoapWebServer::ResetURI( const char* URI )
  46. 46 {
  47. 47 if (URI)
  48. 48 {
  49. 49 m_service.UnRegisteURI(URI);
  50. 50 }
  51. 51 }
  52. 52
  53. 53 void CSoapWebServer::SetURI( const char* URI,RequestProcessFunc fun, void * user)
  54. 54 {
  55. 55 if (!URI || !fun)
  56. 56 {
  57. 57 return;
  58. 58 }
  59. 59
  60. 60 m_service.RegisteURI(URI,fun, user);
  61. 61 }
  62. 62
  63. 63 void CSoapWebServer::SetURI(const char* URI, RequestProcessFunction & fun)
  64. 64 {
  65. 65 if (!URI || !fun)
  66. 66 {
  67. 67 return;
  68. 68 }
  69. 69
  70. 70 m_service.RegisteURI(URI,fun);
  71. 71 }
  72. 72
  73. 73 bool CSoapWebServer::StartService(const char* ip,unsigned int port)
  74. 74 {
  75. 75 //StopService();
  76. 76 m_bExit = false;
  77. 77 do
  78. 78 {
  79. 79 m_pSoap = soap_new();
  80. 80 if (NULL == m_pSoap)
  81. 81 {
  82. 82 break;
  83. 83 }
  84. 84
  85. 85 soap_init1(m_pSoap, SOAP_C_UTFSTRING);
  86. 86 m_pSoap->bind_flags = SO_REUSEADDR;
  87. 87 m_pSoap->send_timeout = SendTimeout;
  88. 88 m_pSoap->recv_timeout = RecvTimeout;
  89. 89 m_pSoap->accept_timeout = AcceptTimeout;
  90. 90 m_pSoap->imode = SOAP_C_UTFSTRING;
  91. 91
  92. 92 m_pSoap->namespaces = namespaces;
  93. 93 soap_set_local_namespaces(m_pSoap);
  94. 94
  95. 95 m_service.Hook(m_pSoap);
  96. 96 {
  97. 97 FreeSoapFunction fun((FreeSoapFunction)std::tr1::bind(
  98. 98 &CSoapWebServer::PushSoap, this, std::tr1::placeholders::_1));
  99. 99 m_service.RegisterFreeSoap(fun);
  100. 100 }
  101. 101
  102. 102 SOAP_SOCKET serverSocket = soap_bind(m_pSoap,ip,port,200);
  103. 103 if (serverSocket == SOAP_INVALID_SOCKET)
  104. 104 {
  105. 105 printf("err soap_bind, %s:%u\n", ip, port);
  106. 106 break;
  107. 107 }
  108. 108 printf("soap bind %s:%u\n", ip, port);
  109. 109
  110. 110 if (!StartThread())
  111. 111 {
  112. 112 printf("err StartThread\n");
  113. 113 break;
  114. 114 }
  115. 115 printf("start success\n");
  116. 116 return true;
  117. 117 } while (false);
  118. 118 printf("err start failed\n");
  119. 119 StopService();
  120. 120 return false;
  121. 121 }
  122. 122 void CSoapWebServer::StopService()
  123. 123 {
  124. 124 m_bExit = true;
  125. 125 CloseThread();
  126. 126 m_iClientCount = 0;
  127. 127
  128. 128 m_service.ClearURI();
  129. 129 FreeSoapAll();
  130. 130 if (NULL != m_pSoap)
  131. 131 {
  132. 132 soap_destroy(m_pSoap);
  133. 133 soap_end(m_pSoap);
  134. 134 soap_done(m_pSoap);
  135. 135 soap_free(m_pSoap);
  136. 136 m_pSoap = NULL;
  137. 137 }
  138. 138 }
  139. 139 bool CSoapWebServer::StartThread()
  140. 140 {
  141. 141 //>开启service接受执行线程
  142. 142 m_ListenThread = new std::thread(
  143. 143 &CSoapWebServer::ServiceListenThread,this);
  144. 144
  145. 145 int iThreadCount = 10;
  146. 146 if( iThreadCount > MaxThreadCount)
  147. 147 {
  148. 148 iThreadCount = MaxThreadCount;
  149. 149 }
  150. 150 else if(iThreadCount == 0)
  151. 151 {
  152. 152 iThreadCount = 1;
  153. 153 }
  154. 154
  155. 155 for (int i = 0; i < iThreadCount; ++i)
  156. 156 {
  157. 157 soap* pSoap = soap_copy(m_pSoap);
  158. 158 THREAD_INFO* info = new(std::nothrow)THREAD_INFO;
  159. 159 if (info == NULL)
  160. 160 {
  161. 161 return false;
  162. 162 }
  163. 163 info->soap_listen = m_pSoap;
  164. 164 info->soap_client = pSoap;
  165. 165 info->pThis = this;
  166. 166 m_ServeThread[i] = new std::thread(
  167. 167 &CSoapWebServer::ServiceServeThread, this, info);
  168. 168 }
  169. 169 return true;
  170. 170 }
  171. 171
  172. 172 void CSoapWebServer::CloseThread()
  173. 173 {
  174. 174 m_cvClient.notify_all();
  175. 175 if (m_ListenThread)
  176. 176 {
  177. 177 m_ListenThread->join();
  178. 178 delete m_ListenThread;
  179. 179 m_ListenThread = nullptr;
  180. 180 }
  181. 181
  182. 182 for (int i = 0; i < MaxThreadCount; i++)
  183. 183 {
  184. 184 if(m_ServeThread[i])
  185. 185 {
  186. 186 m_ServeThread[i]->join();
  187. 187 delete m_ServeThread[i];
  188. 188 m_ServeThread[i] = nullptr;
  189. 189 }
  190. 190 }
  191. 191 }
  192. 192 void CSoapWebServer::ServiceListenThread()
  193. 193 {
  194. 194 Listen();
  195. 195 return ;
  196. 196 }
  197. 197 void CSoapWebServer::Listen()
  198. 198 {
  199. 199 if (NULL == m_pSoap)
  200. 200 {
  201. 201 return ;
  202. 202 }
  203. 203 CLIENT_INFO clientInfo;
  204. 204 while (!m_bExit)
  205. 205 {
  206. 206 clientInfo.socket = soap_accept(m_pSoap);
  207. 207 if (clientInfo.socket != SOAP_INVALID_SOCKET )
  208. 208 {
  209. 209 std::unique_lock<std::mutex> guard(m_listMt);
  210. 210 clientInfo.ip = m_pSoap->ip;
  211. 211 clientInfo.port = m_pSoap->port;
  212. 212 m_acceptClientList.push(clientInfo);
  213. 213 ++m_iClientCount;
  214. 214 m_cvClient.notify_one();
  215. 215 }
  216. 216 }
  217. 217 }
  218. 218
  219. 219 void CSoapWebServer::ServiceServeThread(THREAD_INFO* pParam )
  220. 220 {
  221. 221 if (NULL == pParam)
  222. 222 {
  223. 223 return ;
  224. 224 }
  225. 225 THREAD_INFO* info = (THREAD_INFO*)pParam;
  226. 226 CSoapWebServer *pThis = info->pThis;
  227. 227
  228. 228 if(NULL == pThis)
  229. 229 {
  230. 230 return ;
  231. 231 }
  232. 232 ExecuteServe(info);
  233. 233
  234. 234 delete info;
  235. 235
  236. 236 return ;
  237. 237 }
  238. 238 void CSoapWebServer::ExecuteServe(THREAD_INFO* info )
  239. 239 {
  240. 240 const int iTempSockCount = 1;
  241. 241 CLIENT_INFO tempClientArr[iTempSockCount] = {};
  242. 242 int end_pos = 0;
  243. 243 struct soap* soap = NULL;
  244. 244
  245. 245 soap = info->soap_client;
  246. 246 int ret = SOAP_OK;
  247. 247
  248. 248 while (!m_bExit)
  249. 249 {
  250. 250 {
  251. 251 std::unique_lock<std::mutex> guard(m_listMt);
  252. 252 if (m_acceptClientList.empty())
  253. 253 {
  254. 254 m_cvClient.wait(guard);
  255. 255 }
  256. 256 for (end_pos=0;
  257. 257 end_pos<iTempSockCount && !m_acceptClientList.empty();
  258. 258 ++end_pos )
  259. 259 {
  260. 260 tempClientArr[end_pos] = m_acceptClientList.front();
  261. 261 m_acceptClientList.pop();
  262. 262 --m_iClientCount;
  263. 263 }
  264. 264 }
  265. 265
  266. 266 for (int i = 0 ; i < end_pos; ++i)
  267. 267 {
  268. 268 soap->socket = tempClientArr[i].socket;
  269. 269 soap->ip = tempClientArr[i].ip;
  270. 270 soap->port = tempClientArr[i].port;
  271. 271 if(!soap_valid_socket(soap->socket))
  272. 272 {
  273. 273 continue;
  274. 274 }
  275. 275
  276. 276 if ((ret=BeginServe(soap)) != SOAP_OK)
  277. 277 {
  278. 278 //printf("serve error.code:%d msg:%s\n", soap->error,*(soap_faultstring(soap)));
  279. 279 }
  280. 280
  281. 281 if (ret == SOAP_STOP/*(int)soap->user == RESPONSE_MODE_ASYN*/)
  282. 282 {//异步
  283. 283 //获取一个soap
  284. 284 soap = PopSoap();
  285. 285 if (soap == NULL)
  286. 286 {//缓存没有,拷贝一个
  287. 287 soap = soap_copy(info->soap_listen);
  288. 288 }
  289. 289 }
  290. 290 else
  291. 291 {
  292. 292 EndServe(soap);
  293. 293 }
  294. 294
  295. 295 soap_destroy(soap);
  296. 296 soap_end(soap);
  297. 297 }
  298. 298 }
  299. 299
  300. 300 //回收
  301. 301 PushSoap(soap);
  302. 302 }
  303. 303
  304. 304 int CSoapWebServer::SoapServ( struct soap* soap )
  305. 305 {
  306. 306 #ifndef WITH_FASTCGI
  307. 307 unsigned int k = soap->max_keep_alive;
  308. 308 #endif
  309. 309 do
  310. 310 {
  311. 311 #ifndef WITH_FASTCGI
  312. 312 if (soap->max_keep_alive > 0 && !--k)
  313. 313 {
  314. 314 soap->keep_alive = 0;
  315. 315 }
  316. 316 #endif
  317. 317 if (soap_begin_serve(soap))
  318. 318 {
  319. 319 if (soap->error >= SOAP_STOP)
  320. 320 {
  321. 321 continue;
  322. 322 }
  323. 323 return soap->error;
  324. 324 }
  325. 325
  326. 326 #ifdef WITH_FASTCGI
  327. 327 soap_destroy(soap);
  328. 328 soap_end(soap);
  329. 329 } while (1);
  330. 330 #else
  331. 331 } while (soap->keep_alive);
  332. 332 #endif
  333. 333 return SOAP_OK;
  334. 334 }
  335. 335
  336. 336 int CSoapWebServer::BeginServe(struct soap* soap)
  337. 337 {
  338. 338 void * user = soap->user;
  339. 339 long ret = RESPONSE_MODE_SYN;
  340. 340
  341. 341 soap_begin(soap);
  342. 342 if (soap_begin_recv(soap)
  343. 343 || soap_envelope_begin_in(soap)
  344. 344 || soap_recv_header(soap)
  345. 345 || soap_body_begin_in(soap))
  346. 346 { if (soap->error < SOAP_STOP)
  347. 347 {
  348. 348 #ifdef WITH_FASTCGI
  349. 349 (void)soap_send_fault(soap);
  350. 350 #else
  351. 351 return soap_send_fault(soap);
  352. 352 #endif
  353. 353 }
  354. 354 }
  355. 355
  356. 356 ret = (long)soap->user;
  357. 357 soap->user = user;
  358. 358
  359. 359 return (ret==RESPONSE_MODE_ASYN) ? SOAP_STOP: SOAP_OK;
  360. 360 }
  361. 361
  362. 362 int CSoapWebServer::EndServe(struct soap* soap)
  363. 363 {
  364. 364 return soap_closesock(soap);
  365. 365 }
  366. 366
  367. 367 struct soap* CSoapWebServer::PopSoap(void)
  368. 368 {
  369. 369 struct soap * soap = NULL;
  370. 370 std::unique_lock<std::mutex> guard(m_listMt);
  371. 371 if (m_soapList.empty())
  372. 372 {
  373. 373 return NULL;
  374. 374 }
  375. 375 soap = m_soapList.front();
  376. 376 m_soapList.pop();
  377. 377
  378. 378 return soap;
  379. 379 }
  380. 380
  381. 381 void CSoapWebServer::PushSoap(struct soap* soap)
  382. 382 {
  383. 383 if (soap == NULL)
  384. 384 {
  385. 385 return ;
  386. 386 }
  387. 387
  388. 388 std::unique_lock<std::mutex> guard(m_listMt);
  389. 389 m_soapList.push(soap);
  390. 390 }
  391. 391
  392. 392 void CSoapWebServer::FreeSoapAll(void)
  393. 393 {
  394. 394 std::queue<struct soap*> lsoap;
  395. 395 {
  396. 396 std::unique_lock<std::mutex> guard(m_listMt);
  397. 397 lsoap = m_soapList;
  398. 398 while (!m_soapList.empty())
  399. 399 {
  400. 400 m_soapList.pop();
  401. 401 }
  402. 402 }
  403. 403
  404. 404 struct soap * soap;
  405. 405 while (!lsoap.empty())
  406. 406 {
  407. 407 soap = lsoap.front();
  408. 408
  409. 409 soap_destroy(soap);
  410. 410 soap_end(soap);
  411. 411
  412. 412 soap_done(soap);
  413. 413 soap_free(soap);
  414. 414
  415. 415 lsoap.pop();
  416. 416 }
  417. 417 }
View Code

6.插件头文件

  1. 1 #ifndef RestServicePlugin_CEDAF949_DFA9_4D71_95EE_8EE7A7B2BAAB_H__
  2. 2 #define RestServicePlugin_CEDAF949_DFA9_4D71_95EE_8EE7A7B2BAAB_H__
  3. 3
  4. 4 #include <string>
  5. 5 #include <map>
  6. 6 #include <mutex>
  7. 7
  8. 8 #if (defined _WIN32 || defined _WIN64)
  9. 9 # include <memory> //shared_ptr
  10. 10 # include <functional>
  11. 11 #elif defined(__linux__)
  12. 12 # include <tr1/memory>
  13. 13 # include <tr1/functional>
  14. 14 #endif
  15. 15
  16. 16 #include "stdsoap2.h"
  17. 17 #include "httpget.h"
  18. 18 #include "httppost.h"
  19. 19
  20. 20 namespace Http
  21. 21 {
  22. 22 class CRestServicePlugin;
  23. 23 class Request;
  24. 24
  25. 25 typedef int (*RequestProcessFunc)(Request& request, void* user);
  26. 26 typedef std::tr1::function<int(Request& request)> RequestProcessFunction;
  27. 27 typedef std::tr1::function<void(struct soap*)> FreeSoapFunction;
  28. 28
  29. 29 enum HTTP_STATUS
  30. 30 {
  31. 31 HTTP_STATUS_OK = 0,
  32. 32 HTTP_STATUS_BAD_REQUEST = 400, // invalid syntax
  33. 33 HTTP_STATUS_DENIED = 401, // access denied
  34. 34 HTTP_STATUS_PAYMENT_REQ = 402, // payment required
  35. 35 HTTP_STATUS_FORBIDDEN = 403, // request forbidden
  36. 36 HTTP_STATUS_NOT_FOUND = 404, // object not found
  37. 37 HTTP_STATUS_BAD_METHOD = 405, // method is not allowed
  38. 38 HTTP_STATUS_NONE_ACCEPTABLE = 406, // no response acceptable to client found
  39. 39 HTTP_STATUS_PROXY_AUTH_REQ = 407, // proxy authentication required
  40. 40 HTTP_STATUS_REQUEST_TIMEOUT = 408, // server timed out waiting for request
  41. 41 HTTP_STATUS_CONFLICT = 409, // user should resubmit with more info
  42. 42 HTTP_STATUS_GONE = 410, // the resource is no longer available
  43. 43 HTTP_STATUS_LENGTH_REQUIRED = 411, // the server refused to accept request w/o a length
  44. 44 HTTP_STATUS_PRECOND_FAILED = 412, // precondition given in request failed
  45. 45 HTTP_STATUS_REQUEST_TOO_LARGE = 413, // request entity was too large
  46. 46 HTTP_STATUS_URI_TOO_LONG = 414, // request URI too long
  47. 47 HTTP_STATUS_UNSUPPORTED_MEDIA = 415, // unsupported media type
  48. 48 HTTP_STATUS_RETRY_WITH = 449, // retry after doing the appropriate action.
  49. 49
  50. 50 HTTP_STATUS_SERVER_ERROR = 500 ,// internal server error
  51. 51 HTTP_STATUS_NOT_SUPPORTED = 501, // required not supported
  52. 52 HTTP_STATUS_BAD_GATEWAY = 502, // error response received from gateway
  53. 53 HTTP_STATUS_SERVICE_UNAVAIL = 503, // temporarily overloaded
  54. 54 HTTP_STATUS_GATEWAY_TIMEOUT = 504, // timed out waiting for gateway
  55. 55 HTTP_STATUS_VERSION_NOT_SUP = 505 // HTTP version not supported
  56. 56 };
  57. 57
  58. 58 enum HTTP_METHOD
  59. 59 {
  60. 60 HTTP_GET = 0,
  61. 61 HTTP_POST = 1
  62. 62 };
  63. 63 enum HTTP_RES_TYPE
  64. 64 {
  65. 65 HTTP_HTML = 0,
  66. 66 HTTP_FILE = 1
  67. 67 };
  68. 68 typedef struct rest_str_s
  69. 69 {
  70. 70 size_t len; //字符串长度
  71. 71 char* ptr; //字符串首地址
  72. 72 }rest_str_t;
  73. 73
  74. 74 typedef struct rest_query_s
  75. 75 {
  76. 76 const char* key;
  77. 77 const char* value;
  78. 78 }rest_query_t;
  79. 79
  80. 80 static const size_t QUERY_MAX_SIZE = 20; //最多参数个数
  81. 81
  82. 82 class Request
  83. 83 {
  84. 84 friend class CRestServicePlugin;
  85. 85 friend class Response;
  86. 86 public:
  87. 87 Request()
  88. 88 {
  89. 89 soap = NULL;
  90. 90 }
  91. 91
  92. 92 /** @fn Query
  93. 93 * @brief 获取url中的请求参数
  94. 94 * @param key:
  95. 95 * @return 返回查询到的值
  96. 96 */
  97. 97 const char* Query( const char* key);
  98. 98
  99. 99 /** @fn GetBody
  100. 100 * @brief 获取请求体
  101. 101 * @param
  102. 102 * @return 请求内容字节数,0为空
  103. 103 */
  104. 104 size_t GetBody(char** body);
  105. 105
  106. 106 HTTP_METHOD GetMethod(void){ return method;}
  107. 107
  108. 108 protected:
  109. 109 /** @fn GetURI
  110. 110 * @brief 获取请求的url
  111. 111 * @param
  112. 112 * @return
  113. 113 */
  114. 114 const char* GetURI();
  115. 115
  116. 116 int ReponseWithEnd(int code);
  117. 117 /************************************
  118. 118 >@ Method: ParseRequest
  119. 119 >@ FullName: Http::Request::ParseRequest
  120. 120 >@ Brief: 解析请求参数
  121. 121 >@ Access: public
  122. 122 >@ Returns: bool
  123. 123 >@ Qualifier:
  124. 124 ************************************/
  125. 125 bool ParseRequest();
  126. 126
  127. 127 rest_query_t* GetQuery(void){return _query;}
  128. 128
  129. 129 private:
  130. 130 rest_query_t _query[QUERY_MAX_SIZE];//请求参数
  131. 131 HTTP_METHOD method;
  132. 132 struct soap* soap;
  133. 133 CRestServicePlugin * _plugin;
  134. 134 };
  135. 135
  136. 136 #define RESPONSE_MODE_SYN 0 //同步
  137. 137 #define RESPONSE_MODE_ASYN 1 //异步
  138. 138
  139. 139 class Response
  140. 140 {
  141. 141 public:
  142. 142 Response(Request& req, int mod=RESPONSE_MODE_SYN);
  143. 143 Response();
  144. 144 ~Response();
  145. 145
  146. 146 /** @fn SetContentType
  147. 147 * @brief 设置响应内容,默认为空,例如"text/json"
  148. 148 * @param
  149. 149 * @return
  150. 150 */
  151. 151 void SetContentType(const char* conttype);
  152. 152
  153. 153 /** @fn Send
  154. 154 * @brief 发送响应数据,可以调用多次发送
  155. 155 * @param
  156. 156 * @return 0-发送成功
  157. 157 */
  158. 158 int Send(const char* data);
  159. 159 int Send(const char* data, std::size_t len);
  160. 160
  161. 161 /** @fn BeginResponse
  162. 162 * @brief 开始响应
  163. 163 * @param mod:响应模式,RESPONSE_MODE_SYN-同步,RESPONSE_MODE_ASYN-异步
  164. 164 * @return
  165. 165 */
  166. 166 int BeginResponse(Request& req, int mod=RESPONSE_MODE_SYN);
  167. 167 int EndResponse(void);
  168. 168
  169. 169 protected:
  170. 170
  171. 171
  172. 172 private:
  173. 173 struct soap * _soap;
  174. 174 int _mod;
  175. 175 CRestServicePlugin *_plugin;
  176. 176 };
  177. 177
  178. 178 class CRestServicePlugin
  179. 179 {
  180. 180 friend class Response;
  181. 181 public:
  182. 182 CRestServicePlugin(void);
  183. 183 ~CRestServicePlugin(void);
  184. 184
  185. 185 static int http_get_handler(struct soap*);
  186. 186 static int http_post_text_handler(struct soap *soap);
  187. 187 public:
  188. 188 bool Hook(struct soap* soap);
  189. 189 void RegisteURI(const char* URI,RequestProcessFunc fun, void* user);
  190. 190 void RegisteURI(const char* URI, RequestProcessFunction & fun);
  191. 191 void UnRegisteURI(const char* URI);
  192. 192 void ClearURI();
  193. 193
  194. 194 void RegisterFreeSoap(FreeSoapFunction & fun);
  195. 195 protected:
  196. 196 int Process(struct soap* soap,HTTP_METHOD method);
  197. 197 private:
  198. 198 std::mutex m_dataMt;
  199. 199 //uri的处理函数映射表
  200. 200 std::map<std::size_t,RequestProcessFunction> m_uriFunMap;
  201. 201 FreeSoapFunction _funFreeSoap;
  202. 202 };
  203. 203 }
  204. 204
  205. 205 #endif // RestServicePlugin_CEDAF949_DFA9_4D71_95EE_8EE7A7B2BAAB_H__
View Code
  1. 7.插件cpp文件
  1. 1 #include "RestServicePlugin.h"
  2. 2 #include "httpget.h"
  3. 3
  4. 4
  5. 5 namespace Http
  6. 6 {
  7. 7 static const char* json_type = "application/json";
  8. 8 static const char* http_unknow = "HTTP/1.1 -1 UNKNOW\r\nConnection: close\r\n\r\n";
  9. 9 static const char* http_400 = "HTTP/1.1 400 BAD REQUEST\r\nConnection: close\r\n\r\n";
  10. 10 static const char* http_404 = "HTTP/1.1 404 NOT FOUND\r\nConnection: close\r\n\r\n";
  11. 11 static const char* http_500 = "HTTP/1.1 500 SERVER ERROR\r\nConnection: close\r\n\r\n";
  12. 12
  13. 13 //FNV hash copy from gcc
  14. 14 // Dummy generic implementation (for sizeof(size_t) != 4, 8).
  15. 15 template<std::size_t = sizeof(std::size_t)>
  16. 16 struct Fnv_hash
  17. 17 {
  18. 18 static std::size_t
  19. 19 hash(const char* first, std::size_t length)
  20. 20 {
  21. 21 std::size_t result = 0;
  22. 22 for (; length > 0; --length)
  23. 23 result = (result * 131) + *first++;
  24. 24 return result;
  25. 25 }
  26. 26 };
  27. 27
  28. 28 template<>
  29. 29 struct Fnv_hash<4>
  30. 30 {
  31. 31 static std::size_t
  32. 32 hash(const char* first, std::size_t length)
  33. 33 {
  34. 34 std::size_t result = static_cast<std::size_t>(2166136261UL);
  35. 35 for (; length > 0; --length)
  36. 36 {
  37. 37 result ^= (std::size_t)*first++;
  38. 38 result *= 16777619UL;
  39. 39 }
  40. 40 return result;
  41. 41 }
  42. 42 };
  43. 43
  44. 44 template<>
  45. 45 struct Fnv_hash<8>
  46. 46 {
  47. 47 static std::size_t
  48. 48 hash(const char* first, std::size_t length)
  49. 49 {
  50. 50 std::size_t result = static_cast<std::size_t>(14695981039346656037ULL);
  51. 51 for (; length > 0; --length)
  52. 52 {
  53. 53 result ^= (std::size_t)*first++;
  54. 54 result *= 1099511628211ULL;
  55. 55 }
  56. 56 return result;
  57. 57 }
  58. 58 };
  59. 59
  60. 60
  61. 61 http_post_handlers handlers[] =
  62. 62 {
  63. 63 { "POST", Http::CRestServicePlugin::http_post_text_handler },
  64. 64 { NULL }
  65. 65 };
  66. 66
  67. 67 //////////////////////////////////////////////////////////////////////////
  68. 68 //CRestServicePlugin
  69. 69 CRestServicePlugin::CRestServicePlugin(void)
  70. 70
  71. 71 {
  72. 72 }
  73. 73
  74. 74 CRestServicePlugin::~CRestServicePlugin(void)
  75. 75 {
  76. 76 }
  77. 77
  78. 78 bool CRestServicePlugin::Hook( struct soap* soap )
  79. 79 {
  80. 80 if (NULL == soap)
  81. 81 {
  82. 82 return false;
  83. 83 }
  84. 84 soap->user = (void*)this;
  85. 85 soap_register_plugin_arg(soap, http_get, (void*)http_get_handler);
  86. 86 soap_register_plugin_arg(soap,http_post,(void*)handlers);
  87. 87 return true;
  88. 88 }
  89. 89
  90. 90 void CRestServicePlugin::RegisteURI( const char* URI,RequestProcessFunc fun , void* user)
  91. 91 {
  92. 92 std::tr1::function<int(Request& request)> funl;
  93. 93 funl = std::tr1::bind(fun, std::tr1::placeholders::_1, user);
  94. 94
  95. 95 RegisteURI(URI, funl);
  96. 96 }
  97. 97
  98. 98 void CRestServicePlugin::RegisteURI(const char* URI, RequestProcessFunction & fun)
  99. 99 {
  100. 100 size_t hash_uri = Fnv_hash<>::hash(URI, strlen(URI));
  101. 101
  102. 102 std::lock_guard<std::mutex> guard(m_dataMt);
  103. 103 std::map<size_t, RequestProcessFunction>::iterator iter = m_uriFunMap.find(hash_uri);
  104. 104 if (iter != m_uriFunMap.end())
  105. 105 {
  106. 106 iter->second = fun;
  107. 107 }
  108. 108 else
  109. 109 {
  110. 110 m_uriFunMap.insert(std::map<size_t,RequestProcessFunction>::value_type(hash_uri,fun));
  111. 111 }
  112. 112 }
  113. 113
  114. 114 void CRestServicePlugin::RegisterFreeSoap(FreeSoapFunction & fun)
  115. 115 {
  116. 116 _funFreeSoap = fun;
  117. 117 }
  118. 118
  119. 119 void CRestServicePlugin::UnRegisteURI( const char* URI )
  120. 120 {
  121. 121 size_t hash_uri = Fnv_hash<>::hash(URI, strlen(URI));
  122. 122
  123. 123 std::lock_guard<std::mutex> guard(m_dataMt);
  124. 124 std::map<size_t,RequestProcessFunction>::iterator iter = m_uriFunMap.find(hash_uri);
  125. 125 if (iter != m_uriFunMap.end())
  126. 126 {
  127. 127 m_uriFunMap.erase(iter);
  128. 128 }
  129. 129 }
  130. 130
  131. 131 void CRestServicePlugin::ClearURI()
  132. 132 {
  133. 133 std::lock_guard<std::mutex> guard(m_dataMt);
  134. 134 m_uriFunMap.clear();
  135. 135 _funFreeSoap = NULL;
  136. 136 }
  137. 137
  138. 138 int CRestServicePlugin:: http_get_handler(struct soap* soap)
  139. 139 {
  140. 140 if (soap == NULL || soap->user == NULL)
  141. 141 {
  142. 142 return SOAP_ERR;
  143. 143 }
  144. 144 Http::CRestServicePlugin* pThis = (CRestServicePlugin*)soap->user;
  145. 145 return pThis->Process(soap,HTTP_GET);
  146. 146 }
  147. 147
  148. 148 /* the text handler copies the message back */
  149. 149 int CRestServicePlugin:: http_post_text_handler(struct soap *soap)
  150. 150 {
  151. 151 if (soap == NULL || soap->user == NULL)
  152. 152 {
  153. 153 return SOAP_ERR;
  154. 154 }
  155. 155 Http::CRestServicePlugin* pThis = (CRestServicePlugin*)soap->user;
  156. 156 return pThis->Process(soap,HTTP_POST);
  157. 157 }
  158. 158
  159. 159 int CRestServicePlugin::Process( struct soap* soap ,HTTP_METHOD method)
  160. 160 {
  161. 161 Request request;
  162. 162 request.method = method;
  163. 163 request.soap = soap;
  164. 164 request._plugin = this;
  165. 165
  166. 166 std::tr1::function<int(Request& request)> *fun = NULL;
  167. 167 {
  168. 168 char* uri = query(soap);
  169. 169 size_t hash_uri = Fnv_hash<>::hash(soap->path, uri? (uri-soap->path): strlen(soap->path));
  170. 170
  171. 171 std::lock_guard<std::mutex> guard(m_dataMt);
  172. 172 std::map<size_t,RequestProcessFunction>::iterator iter = m_uriFunMap.find(hash_uri);
  173. 173 if (iter != m_uriFunMap.end())
  174. 174 {
  175. 175 fun = &iter->second;
  176. 176 }
  177. 177 }
  178. 178
  179. 179 if(!request.ParseRequest() || fun==NULL)
  180. 180 {
  181. 181 return request.ReponseWithEnd(HTTP_STATUS_NOT_FOUND);
  182. 182 }
  183. 183 return (*fun)(request);
  184. 184 }
  185. 185
  186. 186 //////////////////////////////////////////////////////////////////////////
  187. 187 //Request
  188. 188 const char* Request::GetURI( )
  189. 189 {
  190. 190 return soap->path;
  191. 191 }
  192. 192 bool Request::ParseRequest()
  193. 193 {
  194. 194 char *s;
  195. 195 s = query(soap);
  196. 196 int i = 0;
  197. 197 while (s && s[0] != '\0' && i<QUERY_MAX_SIZE)
  198. 198 {
  199. 199 char *key = query_key(soap,&s);
  200. 200 if (key == NULL)
  201. 201 {
  202. 202 continue;
  203. 203 }
  204. 204 char* val = query_val(soap,&s);
  205. 205 if (val == NULL)
  206. 206 {
  207. 207 continue;
  208. 208 }
  209. 209
  210. 210 _query[i].key = key;
  211. 211 _query[i].value = val;
  212. 212 ++i;
  213. 213 }
  214. 214
  215. 215 if (i<QUERY_MAX_SIZE)
  216. 216 {//最后一个初始化为空
  217. 217 _query[i].key = NULL;
  218. 218 }
  219. 219
  220. 220 return true;
  221. 221 }
  222. 222
  223. 223 const char* Request::Query( const char* key)
  224. 224 {
  225. 225 if (key == NULL)
  226. 226 {
  227. 227 return NULL;
  228. 228 }
  229. 229
  230. 230 int i = 0;
  231. 231 while (i<QUERY_MAX_SIZE && _query[i].key!=NULL)
  232. 232 {
  233. 233 if (strcmp(_query[i].key, key) == 0)
  234. 234 {
  235. 235 return _query[i].value;
  236. 236 }
  237. 237 ++i;
  238. 238 }
  239. 239
  240. 240 return NULL;
  241. 241 }
  242. 242
  243. 243 int Request::ReponseWithEnd( int code )
  244. 244 {
  245. 245 const char* res = NULL;
  246. 246 switch(code)
  247. 247 {
  248. 248 case HTTP_STATUS_BAD_REQUEST:
  249. 249 res = http_400;
  250. 250 break;
  251. 251 case HTTP_STATUS_NOT_FOUND:
  252. 252 res = http_404;
  253. 253 break;
  254. 254 case HTTP_STATUS_SERVER_ERROR:
  255. 255 res = http_500;
  256. 256 break;
  257. 257 default:
  258. 258 res = http_unknow;
  259. 259 break;
  260. 260 }
  261. 261 soap_send(soap,res);
  262. 262 soap_end_send(soap);
  263. 263
  264. 264 return SOAP_OK;
  265. 265 }
  266. 266
  267. 267 size_t Request::GetBody(char** body )
  268. 268 {
  269. 269 size_t len = 0;
  270. 270 if(SOAP_OK != soap_http_body(soap, body, &len))
  271. 271 {
  272. 272 return 0;
  273. 273 }
  274. 274
  275. 275 return len;
  276. 276 }
  277. 277
  278. 278 //////////////////////////////////////////////////////////////////////////
  279. 279 //response
  280. 280 Response::Response()
  281. 281 {
  282. 282 _soap = NULL;
  283. 283 _mod = RESPONSE_MODE_SYN;
  284. 284 //soap->user = RESPONSE_MODE_SYN;
  285. 285 _plugin = NULL;
  286. 286 }
  287. 287
  288. 288 Response::Response(Request& req, int mod)
  289. 289 {
  290. 290 _soap = NULL;
  291. 291
  292. 292 BeginResponse(req, mod);
  293. 293 }
  294. 294
  295. 295 Response::~Response()
  296. 296 {
  297. 297 EndResponse();
  298. 298 }
  299. 299
  300. 300 void Response::SetContentType(const char* conttype)
  301. 301 {
  302. 302 _soap->http_content = conttype;
  303. 303 }
  304. 304
  305. 305 int Response::Send(const char* data)
  306. 306 {
  307. 307 return Send(data, strlen(data));
  308. 308 }
  309. 309
  310. 310 int Response::Send(const char* data, std::size_t len)
  311. 311 {
  312. 312 return soap_send_raw(_soap, data, len);
  313. 313 }
  314. 314
  315. 315 int Response::BeginResponse(Request& req, int mod)
  316. 316 {
  317. 317 EndResponse();
  318. 318
  319. 319 _soap = req.soap;
  320. 320 _mod = mod;
  321. 321 _soap->user = (void*)_mod;
  322. 322 _plugin = req._plugin;
  323. 323
  324. 324 return soap_response(_soap ,SOAP_FILE);
  325. 325 }
  326. 326
  327. 327 int Response::EndResponse(void)
  328. 328 {
  329. 329 int ret = SOAP_OK;
  330. 330 if (_soap == NULL)
  331. 331 {
  332. 332 return SOAP_OK;
  333. 333 }
  334. 334
  335. 335 ret = soap_end_send(_soap);
  336. 336
  337. 337 if (_mod == RESPONSE_MODE_ASYN)
  338. 338 {//如果是异步模式,需要释放
  339. 339 soap_destroy(_soap);
  340. 340 soap_end(_soap);
  341. 341 if (_plugin->_funFreeSoap)
  342. 342 {
  343. 343 _plugin->_funFreeSoap(_soap);
  344. 344 }
  345. 345 else
  346. 346 {
  347. 347 soap_done(_soap);
  348. 348 soap_free(_soap);
  349. 349 }
  350. 350 }
  351. 351
  352. 352 _soap = NULL;
  353. 353 _mod = RESPONSE_MODE_SYN;
  354. 354 _plugin = NULL;
  355. 355
  356. 356 return ret;
  357. 357 }
  358. 358
  359. 359 }//namespace Http
View Code
  1. 8.使用例子
  1. 1 #include "./web/SoapWebServer.h"
  2. 2 #include "cJSON.h"
  3. 3
  4. 4 #include <thread>
  5. 5
  6. 6 bool static copy_file(Response* res, const char *name)
  7. 7 {
  8. 8 FILE *fd;
  9. 9 size_t r;
  10. 10 fd = fopen(name, "rb"); /* open file to copy */
  11. 11 if (!fd)
  12. 12 return false; /* return HTTP not found */
  13. 13
  14. 14 int tmpbuf_len = 512;
  15. 15 char *tmpbuf = new char[tmpbuf_len];
  16. 16
  17. 17 for (;;)
  18. 18 {
  19. 19 r = fread(tmpbuf, 1, tmpbuf_len, fd);
  20. 20 if (!r)
  21. 21 break;
  22. 22 if (res->Send(tmpbuf, r))
  23. 23 {//发送失败
  24. 24 fclose(fd);
  25. 25 return false;
  26. 26 }
  27. 27 //Sleep(70);
  28. 28 }
  29. 29 delete []tmpbuf;
  30. 30 fclose(fd);
  31. 31
  32. 32 return true;
  33. 33 }
  34. 34
  35. 35 void ThreadResponseImg(Response* res)
  36. 36 {
  37. 37 bool bret = false;
  38. 38
  39. 39 res->SetContentType("image/jpeg");
  40. 40 bret = copy_file(res, "E:\\test\\testimage\\v1.jpg");
  41. 41
  42. 42 //printf("发送文件 %s\n", bret?"成功":"失败");
  43. 43
  44. 44 delete res;
  45. 45 }
  46. 46
  47. 47 static int api_login(Request &req, void *user)
  48. 48 {
  49. 49 char * body = NULL;
  50. 50 if (req.GetBody(&body))
  51. 51 {
  52. 52 printf("request login=%s\n", body);
  53. 53 }
  54. 54
  55. 55 cJSON *jsonRes = NULL;
  56. 56 jsonRes = cJSON_CreateObject();
  57. 57 cJSON_AddNumberToObject(jsonRes, "errorCode", 0);
  58. 58 cJSON_AddStringToObject(jsonRes, "token", "fd90bba04662411f86d8936900131936");
  59. 59 char * str = cJSON_Print(jsonRes);
  60. 60
  61. 61 Response resp(req);
  62. 62 resp.Send(str);
  63. 63
  64. 64 cJSON_Delete(jsonRes);
  65. 65 free(str);
  66. 66
  67. 67 return 0;
  68. 68 }
  69. 69
  70. 70
  71. 71 class print_json
  72. 72 {
  73. 73 public:
  74. 74 print_json()
  75. 75 {
  76. 76 //printf("cons print_json \n");
  77. 77 }
  78. 78 ~print_json()
  79. 79 {
  80. 80 printf("des print_json\n");
  81. 81 }
  82. 82 int print_person(Request &req)
  83. 83 {
  84. 84 Response res(req);
  85. 85 res.SetContentType("application/json; charset=utf-8");
  86. 86 res.Send("{\"print_person\" : 10}");
  87. 87
  88. 88 return 0;
  89. 89 }
  90. 90
  91. 91 int print_query(Request &req)
  92. 92 {
  93. 93 Response res(req);
  94. 94 res.SetContentType("application/json; charset=utf-8");
  95. 95 res.Send("{\"print_query\" : 10}");
  96. 96
  97. 97 /*for (rest_query_t *q = req.GetQuery(); q->key; ++q)
  98. 98 {
  99. 99 printf("key-%s,val-%s", q->key, q->value);
  100. 100 }*/
  101. 101 printf("\n");
  102. 102
  103. 103 return 0;
  104. 104 }
  105. 105
  106. 106 int print_img(Request &req)
  107. 107 {
  108. 108 Response *res = new Response;
  109. 109 res->BeginResponse(req, RESPONSE_MODE_SYN);
  110. 110
  111. 111 ThreadResponseImg(res); //同步
  112. 112
  113. 113 //这里可以开启线程进行异步发送RESPONSE_MODE_ASYN
  114. 114 //std::thread t1(ThreadResponseImg, res);
  115. 115 //t1.detach();
  116. 116
  117. 117 return 0;
  118. 118 }
  119. 119
  120. 120 protected:
  121. 121 private:
  122. 122 };
  123. 123
  124. 124 int main(int argc, char* argv[])
  125. 125 {
  126. 126 print_json pt;
  127. 127 CSoapWebServer web;
  128. 128 const char* host = "0.0.0.0";
  129. 129 unsigned port = 56789;
  130. 130 web.StartService(host, port);
  131. 131 printf("start listen %s:%u\n", host, port);
  132. 132
  133. 133 //tr1 bug 不能把bind作为参数传递
  134. 134 //web.SetURI("/json", std::tr1::bind(&print_json::print, &pt, std::tr1::placeholders::_1));
  135. 135 web.SetURI("/json", (RequestProcessFunction)std::tr1::bind(
  136. 136 &print_json::print_person, &pt, std::tr1::placeholders::_1));
  137. 137 web.SetURI("/json1", (RequestProcessFunction)std::tr1::bind(
  138. 138 &print_json::print_query, &pt, std::tr1::placeholders::_1));
  139. 139
  140. 140 web.SetURI("/img", (RequestProcessFunction)std::tr1::bind(
  141. 141 &print_json::print_img, &pt, std::tr1::placeholders::_1));
  142. 142
  143. 143 web.SetURI("/login", api_login, NULL);
  144. 144
  145. 145 getchar();
  146. 146
  147. 147 web.StopService();
  148. 148
  149. 149 return 0;
  150. 150 }
View Code

 


在浏览器中访问接口:
http://127.0.0.1:56789/json
这个接口返回json内容:

{"print_person" : 10}

 

http://127.0.0.1:56789/img
这个接口返回的是一张图片

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号