利用gsoap库封装易用的rest框架
程序员文章站
2023-11-06 14:46:46
c++缺少web开发的框架,web框架分为异步和同步,异步的业务逻辑控制需要较强功底,同步代码实现起来容易,利于阅读理解 1.gsoap是c++写的webservice库,webservice应用层也是用http进行传输的,gsoap提供了httpget和httppost的插件,本文对这两个插件进行 ......
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
这个接口返回的是一张图片