利用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__
View Code
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 }
View Code

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__
View Code
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
View Code
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 }
View Code

 


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

{"print_person" : 10}

 

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

posted on 2018-11-23 13:45  lijianbo  阅读(1501)  评论(0编辑  收藏  举报

导航