欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

利用gsoap库封装易用的rest框架

程序员文章站 2022-06-12 07:59:30
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文件

利用gsoap库封装易用的rest框架
 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__
view code
5.server.cpp文件
利用gsoap库封装易用的rest框架
  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 }
view code

6.插件头文件

利用gsoap库封装易用的rest框架
  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__
view code
7.插件cpp文件
利用gsoap库封装易用的rest框架
  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
view code
8.使用例子
利用gsoap库封装易用的rest框架
  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 }
view code

 


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

{"print_person" : 10}

 

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