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