ACE+gSOAP实现高性能WebService Server(C/C++)

来源:互联网 发布:如何设置淘宝宝贝模板 编辑:程序博客网 时间:2024/04/29 08:18

1、开发环境请参考《搭建ACE-5.7.4+VS2008开发环境》一文

 

2、gSOAP库,下载地址:http://gsoap2.sourceforge.net/,本文使用的版本是:gsoap_2.7.15,gSOAP的编程可以参考doc目录下的soapdoc2.pdf,官方文档写的非常详细。

 

让我们开始gSOAP编码旅程:

 

1、创建gsoap_server.h:

[cpp] view plaincopy
  1. //gsoap ns2 service namespace:  http://localhost:9908/ccm_mimport/services.wsdl  
  2. //gsoap ns2 service location:   http://localhost:9908/ccm_mimport/services  
  3.   
  4. typedef char * xsd__string; // encode char * value as the xsd:string schema type   
  5. typedef int xsd__int; // encode xsd__int value as the xsd:int schema typ  
  6.   
  7. struct ns2__makeCardNotifyReqBean  
  8. {  
  9.     xsd__string id_makecard_order;  
  10.     xsd__int card_type;  
  11.     xsd__string file_name;  
  12.     xsd__string start_card_serial;  
  13.     xsd__string end_card_serial;  
  14.     xsd__int card_count;  
  15. };  
  16.   
  17. struct ns2__makeCardNotifyRspBean  
  18. {  
  19.     xsd__int result; //结果  
  20.     xsd__string error_desc; //错误描述  
  21. };  
  22.   
  23. //卡数据生成结果通知接口  
  24. int ns2__makeCardNotify(struct ns2__makeCardNotifyReqBean req, struct ns2__makeCardNotifyRspBean *rsp);  

 

注:头文件上面的注释用于配置服务访问地址,而非单纯的注释;详细配置说明可以参考官方文档

 

2、把%GSOAP_HOME%/gsoap/bin/win32目录配置到系统%Path%里,或者将目录下的soapcpp2.exe和wsdl2h.exe两个文件直接拷贝到gsoap_server.h所在目录;

 

3、编写批处理文件:

[cpp] view plaincopy
  1. echo off  
  2.   
  3. del *.c *.h *.xml *.nsmap *.cpp  
  4.   
  5. soapcpp2 -c -S gsoap_server.h  
  6.   
  7. copy soapC.c ../soapC.cpp  
  8. copy soapServer.c ../soapServer.cpp  
  9. copy soapH.h ../soapH.h  
  10. copy soapStub.h ../soapStub.h  
  11. copy ns2.nsmap ../gsoap_server.nsmap  
  12.   
  13. echo .  
  14.   
  15. echo /******************************/  
  16. echo .  
  17. echo 生成的ns2.wsdl必须删除schemaLocation="http://schemas.xmlsoap.org/soap/encoding/"属性  
  18. echo .  
  19. echo /******************************/  
  20. echo .  
  21.   
  22. pause  

 

4、编写业务实现代码:

[cpp] view plaincopy
  1. #include <ctype.h>  
  2. #include <string>  
  3.   
  4. #include <ace/OS.h>  
  5. #include <ace/OS_NS_ctype.h>  
  6. #include <ace/OS_NS_string.h>  
  7.   
  8. #include "Global_Define.h"  
  9. #include "ffcs_logger.h"  
  10.   
  11. #include "stdsoap2.h"  
  12. #include "soapH.h"  
  13. #include "gsoap_server.nsmap"  
  14.   
  15. extern Logger g_logger;  
  16. extern GlobalValue g_val;  
  17.   
  18.   
  19.   
  20. /*----------------------------------------------------------------------- 
  21. * name:     卡数据生成结果通知接口 
  22. * input:    soap  -- gSOAP运行时环境实例 
  23. *           req  -- SOAP请求参数 
  24. * 
  25. * output:   rsp  -- SOAP应答参数 
  26. * return:   SOAP_OK  -- 成功 
  27. *           SOAP_ERR  -- 失败:将导致客户端接口调用异常,一般不使用  
  28. *-----------------------------------------------------------------------*/  
  29. SOAP_FMAC5 int SOAP_FMAC6 ns2__makeCardNotify(struct soap* soap, struct ns2__makeCardNotifyReqBean req, struct ns2__makeCardNotifyRspBean *rsp)  
  30. {  
  31.     ACE_UINT64 ms_1, ms_2;  
  32.   
  33.     ACE_OS::gettimeofday().msec(ms_1);  
  34.   
  35.     g_logger.debug("*** SOAP请求开始 ***/n");  
  36.   
  37.     if (req.id_makecard_order==NULL || req.file_name==NULL)  
  38.     {  
  39.         g_logger.error("格式无效/n");  
  40.   
  41.         rsp->result = RET_FORMATERROR;  
  42.         rsp->error_desc = "";  
  43.   
  44.         return SOAP_OK;  
  45.     }  
  46.   
  47.     rsp->result = RET_SUCCESS;  
  48.     rsp->error_desc = "成功";  
  49.   
  50.     ACE_OS::gettimeofday().msec(ms_2);  
  51.   
  52.     g_logger.debug("*** SOAP请求结束,耗时 (%ld)ms ***/n", ms_2-ms_1);  
  53.     return SOAP_OK;  
  54. }  

 

5、编写WebService服务端处理代码:

[cpp] view plaincopy
  1. #include <ace/OS.h>  
  2.   
  3. #include "stdsoap2.h"  
  4. #include "soapH.h"  
  5.   
  6. #include "Global_Define.h"  
  7. #include "ffcs_logger.h"  
  8.   
  9. /************************************************************************/  
  10. /* 全局变量                                                             */  
  11.   
  12. Logger g_logger;  
  13. GlobalValue g_val;  
  14.   
  15. /************************************************************************/  
  16.   
  17. static void * pthr_soap_server_process(void * arg);  
  18. static void * pthr_soap_server_process_task(void * arg);  
  19.   
  20. int ACE_TMAIN(int argc, ACE_TCHAR* argv[])  
  21. {  
  22.     g_val.g_sys_run = 1;  
  23.   
  24.     /*初始化日志系统*/  
  25.     g_logger.load_config(CONFIG_FILE);  
  26.     g_logger.open_logger();  
  27.   
  28.     /*加载配置参数*/  
  29.     if (g_val.load_config(CONFIG_FILE) == -1)   
  30.     {  
  31.         g_val.g_sys_run = 0;  
  32.         g_logger.error("Load config file [%s] fail!/n", CONFIG_FILE);  
  33.   
  34.         ACE_OS::exit();  
  35.         return 0;  
  36.     }  
  37.   
  38.     /*启动SOAP服务端,方式一*/  
  39.     /* 
  40.     if (ACE_Thread_Manager::instance()->spawn_n(1, 
  41.                                                 (ACE_THR_FUNC)pthr_soap_server_process,//Execute task one 
  42.                                                 NULL, //arguments 
  43.                                                 THR_NEW_LWP | THR_DETACHED, //New Light Weight Process 
  44.                                                 ACE_DEFAULT_THREAD_PRIORITY, 
  45.                                                 FFCS_SOAP_SERVER_GRPID)==-1) //Group ID 
  46.         g_logger.error("Failure to spawn /"pthr_soap_server_process/" of threads/n"); 
  47.     */  
  48.   
  49.     /*启动SOAP服务端,方式二*/  
  50.     if (ACE_Thread_Manager::instance()->spawn_n(1,  
  51.                                         (ACE_THR_FUNC)pthr_soap_server_process_task,//Execute task one  
  52.                                         NULL, //arguments  
  53.                                         THR_NEW_LWP | THR_DETACHED, //New Light Weight Process  
  54.                                         ACE_DEFAULT_THREAD_PRIORITY,  
  55.                                         FFCS_SOAP_SERVER_GRPID)==-1) //Group ID  
  56.         g_logger.error("Failure to spawn /"pthr_soap_server_process_task/" of threads/n");  
  57.   
  58.     while(g_val.g_sys_run == 1)   
  59.     {  
  60.         ACE_OS::sleep(1);  
  61.     }  
  62.   
  63.     return 0;  
  64. }  
  65.   
  66.   
  67. /*采用线程池的方式处理SOAP Client请求*/  
  68. static void * pthr_soap_server_process(void * arg)  
  69. {  
  70.     char cHost[] = "localhost"//服务器IP  
  71.     int iPort = 9908; //端口  
  72.   
  73.   
  74.   
  75.     struct soap soap;  
  76.     SOAP_SOCKET m, s;  
  77.     int i;  
  78.     struct timespec rqt;  
  79.   
  80.     struct soap *soap_thr[MAX_THR]; // 连接池运行时环境实例  
  81.     ACE_thread_t tid[MAX_THR]; //线程池标识  
  82.   
  83.     //初始化连接池运行时环境实例  
  84.     for (i = 0; i < MAX_THR; i++)   
  85.     {  
  86.         soap_thr[i] = NULL;  
  87.         tid[i] = 0;  
  88.     }  
  89.   
  90.     /*初始化服务*/  
  91.     soap_init(&soap);  
  92.     do   
  93.     {  
  94.         m = soap_bind(&soap, cHost, iPort, BACKLOG);  
  95.         if (!soap_valid_socket(m))   
  96.         {  
  97.             g_logger.error("Socket bind fail (%d);System retry after 10 seconds/n");  
  98.             ACE_OS::sleep(10);  
  99.             continue;  
  100.         }   
  101.         else   
  102.         {  
  103.             g_logger.debug("Socket %d connection successful %s on port %d/n", m, cHost, iPort);  
  104.             break;  
  105.         }  
  106.     } while (g_val.g_sys_run == 1);  
  107.   
  108.     /*处理请求*/  
  109.     while (g_val.g_sys_run == 1)  
  110.     {  
  111.         for (i = 0; i < MAX_THR; i++)   
  112.         {  
  113.             s = soap_accept(&soap);  
  114.             if (!soap_valid_socket(s))   
  115.             {  
  116.                 if (soap.errnum)   
  117.                 {  
  118.                     g_logger.error("SOAP异常:%d/n", soap.errnum);  
  119.                     continue// retry  
  120.                 }   
  121.                 else   
  122.                 {  
  123.                     g_logger.error("Server timed out/n");  
  124.                     break;  
  125.                 }  
  126.             }  
  127.   
  128.             g_logger.debug("Thread %d accepts socket %d connection from IP %d.%d.%d.%d/n", i, s, (soap.ip >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >> 8)&0xFF, soap.ip&0xFF);  
  129.   
  130.             if (!soap_thr[i]) // 首次连接  
  131.             {  
  132.                 soap_thr[i] = soap_copy(&soap);  
  133.                 if (!soap_thr[i])   
  134.                 {  
  135.                     g_logger.error("系统异常/n");  
  136.                     break;  
  137.                 }  
  138.             }   
  139.             else // 循环连接,等待连接池释放资源  
  140.             {   
  141.                 ACE_Thread_Manager::instance()->join(tid[i]);  
  142.                 g_logger.debug("OLD Thread %d completed/n", i);  
  143.                 soap_destroy(soap_thr[i]);  
  144.                 soap_end(soap_thr[i]);  
  145.             }  
  146.   
  147.             soap_thr[i]->socket = s;  
  148.             //设置编码UTF-8  
  149.             soap_set_imode(soap_thr[i], SOAP_C_UTFSTRING);  
  150.   
  151.             /*处理SOAP请求*/  
  152.             tid[i] = ACE_Thread_Manager::instance()->spawn_n(1,  
  153.                                                             (ACE_THR_FUNC)soap_serve,//Execute task one  
  154.                                                             (void*)soap_thr[i], //arguments  
  155.                                                             THR_NEW_LWP | THR_JOINABLE, //New Light Weight Process  
  156.                                                             ACE_DEFAULT_THREAD_PRIORITY,  
  157.                                                             FFCS_SOAP_SERVER_GRPID);  
  158.               
  159.             if (tid[i] == -1) g_logger.error("Failure to spawn /"soap_serve/" of threads/n");  
  160.         }  
  161.   
  162.         rqt.tv_sec = 0;  
  163.         rqt.tv_nsec = 10000000;  
  164.         ACE_OS::nanosleep(&rqt);  
  165.     }  
  166.   
  167.     //释放资源  
  168.     for (i = 0; i < MAX_THR; i++)   
  169.     {  
  170.         if (soap_thr[i])   
  171.         {  
  172.             soap_free(soap_thr[i]); // == soap_done(soap_thr[i]); + free(soap_thr[i]);  
  173.         }  
  174.     }  
  175.   
  176.     soap_done(&soap);   
  177.   
  178.     return 0;  
  179. }  
  180.   
  181. /*采用线程池+消息队列的方式处理SOAP Client请求*/  
  182. static void * pthr_soap_server_process_task(void * arg)  
  183. {  
  184.     char cHost[] = "localhost"//服务器IP  
  185.     int iPort = 9908; //端口  
  186.   
  187.   
  188.   
  189.     struct soap soap;  
  190.     struct soap *pSoap;  
  191.     SOAP_SOCKET m, s;  
  192.     struct timespec rqt;  
  193.   
  194.     TaskSoapClient task_soap_client;  
  195.   
  196.     /*初始化服务*/  
  197.     soap_init(&soap);  
  198.     do   
  199.     {  
  200.         m = soap_bind(&soap, cHost, iPort, BACKLOG);  
  201.         if (!soap_valid_socket(m))   
  202.         {  
  203.             g_logger.error("Socket bind fail (%d);System retry after 10 seconds/n");  
  204.             ACE_OS::sleep(10);  
  205.             continue;  
  206.         }   
  207.         else   
  208.         {  
  209.             g_logger.debug("Socket %d connection successful %s on port %d/n", m, cHost, iPort);  
  210.             break;  
  211.         }  
  212.     } while (g_val.g_sys_run == 1);  
  213.   
  214.     /*创建消息处理ACE_Task*/  
  215.     task_soap_client.set_active(true);  
  216.     if (task_soap_client.activate(THR_NEW_LWP | THR_JOINABLE, TASK_SOAP_CLIENT_POOL_SIZE) == -1)  
  217.     {  
  218.         g_logger.error("TaskSoapClient activate failed/n");  
  219.         return 0;  
  220.     }  
  221.   
  222.     /*处理请求*/  
  223.     while (g_val.g_sys_run == 1)  
  224.     {  
  225.         s = soap_accept(&soap);  
  226.         if (!soap_valid_socket(s))   
  227.         {  
  228.             if (soap.errnum)   
  229.             {  
  230.                 g_logger.error("SOAP异常:%d/n", soap.errnum);  
  231.                 continue// retry  
  232.             }   
  233.             else   
  234.             {  
  235.                 g_logger.error("Server timed out/n");  
  236.                 break;  
  237.             }  
  238.         }  
  239.   
  240.         g_logger.debug("Accepts socket %d connection from IP %d.%d.%d.%d/n", s, (soap.ip >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >> 8)&0xFF, soap.ip&0xFF);  
  241.   
  242.         pSoap = soap_copy(&soap);  
  243.         if (!pSoap)   
  244.         {  
  245.             g_logger.error("系统异常/n");  
  246.             continue;  
  247.         }  
  248.         pSoap->socket = s;  
  249.         //设置编码UTF-8  
  250.         soap_set_imode(pSoap, SOAP_C_UTFSTRING);  
  251.   
  252.         /*放入队列*/  
  253.         task_soap_client.process_soap_client_requet((void *)pSoap);  
  254.   
  255.         rqt.tv_sec = 0;  
  256.         rqt.tv_nsec = 50000000;  
  257.         ACE_OS::nanosleep(&rqt);  
  258.     }  
  259.   
  260.     soap_done(&soap);   
  261.   
  262.     task_soap_client.set_active(false);  
  263.     task_soap_client.msg_queue()->close();  
  264.     task_soap_client.wait();  
  265.   
  266.     return 0;  
  267. }  

 

6、如果采用线程池+消息队列的方式处理SOAP Client请求,需要引入ACE_Task,并采用ACE_Message_Block实现对了操作:

[cpp] view plaincopy
  1. /******************************************************************************************** 
  2. * huangjf 2009年12月 于福州 
  3. ********************************************************************************************/  
  4. #include <ace/OS.h>  
  5.   
  6. #include "Global_Define.h"  
  7. #include "ffcs_logger.h"  
  8. #include "ffcs_common.h"  
  9.   
  10. #include "stdsoap2.h"  
  11. #include "soapH.h"  
  12.   
  13. extern Logger g_logger;  
  14.   
  15.   
  16. /******************************************************************************************** 
  17. * WebService Client Requet 处理类 
  18. ********************************************************************************************/  
  19.   
  20. class TaskSoapClient: public ACE_Task<ACE_MT_SYNCH>  
  21. {  
  22. public:  
  23.     TaskSoapClient() : active_(false)  
  24.     {  
  25.         this->active_ = false;  
  26.         this->msg_queue()->high_water_mark(SOAP_HIGHT_MARK);  
  27.         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) TaskSoapClient start/n")));  
  28.     }  
  29.   
  30.     virtual ~TaskSoapClient()  
  31.     {  
  32.         this->active_ = false;  
  33.         this->msg_queue()->close();  
  34.         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) TaskSoapClient stop/n")));  
  35.     }  
  36.   
  37.     virtual int svc(void);  
  38.   
  39.     bool get_active();  
  40.     void set_active(bool b);  
  41.   
  42.     int process_soap_client_requet(void *soap);  
  43. private:  
  44.     bool active_;  
  45.   
  46.     void process_soap(ACE_Message_Block *mb = NULL);  
  47. };  
  48.   
  49.   
  50. //处理接收队列  
  51. int TaskSoapClient::svc(void)  
  52. {  
  53.     g_logger.debug("TaskSoapClient::svc() start/n");  
  54.   
  55.     while (this->active_==true)  
  56.     {  
  57.         ACE_Message_Block *mb = NULL;  
  58.         if (this->getq(mb) == -1)  
  59.         {  
  60.             /*g_logger.error("取接收队列数据失败/n");*/  
  61.             continue;  
  62.         }  
  63.   
  64.         process_soap(mb);  
  65.     }  
  66.   
  67.     g_logger.debug("TaskSoapClient::svc() stop/n");  
  68.     return 0;  
  69. }  
  70.   
  71. void TaskSoapClient::process_soap(ACE_Message_Block *mb)  
  72. {  
  73.     char * data = mb->rd_ptr();  
  74.     size_t data_size = mb->length();  
  75.   
  76.     /*g_logger.dump(data, data_size, 1);*/  
  77.   
  78.     /**************************************************************** 
  79.     * TODO 处理接收到的SOAP Client Request,数据的起始地址为data,长度为data_size 
  80.     *****************************************************************/  
  81.   
  82.     struct soap * pSoap = NULL;   
  83.   
  84.     try  
  85.     {  
  86.         ACE_OS::memcpy(&pSoap, data, MIN(data_size, sizeof(void *)));  
  87.     }  
  88.     catch (...)  
  89.     {  
  90.         g_logger.error("struct soap * 转换异常/n");  
  91.         return;  
  92.     }  
  93.   
  94.     if (pSoap)  
  95.     {  
  96.         if (!soap_valid_socket(pSoap->socket))   
  97.         {  
  98.             if (pSoap->errnum)   
  99.             {  
  100.                 g_logger.error("SOAP异常:%d/n", pSoap->errnum);  
  101.             }   
  102.             else   
  103.             {  
  104.                 g_logger.error("SOAP异常:??/n");  
  105.             }  
  106.   
  107.             soap_free(pSoap);/*销毁*/  
  108.             return;  
  109.         }  
  110.   
  111.         soap_serve(pSoap);   /*执行*/  
  112.   
  113.         soap_destroy(pSoap); /*释放*/  
  114.         soap_end(pSoap);     /*释放*/  
  115.   
  116.         soap_free(pSoap);    /*销毁*/  
  117.     }  
  118.   
  119.   
  120.   
  121.     //数据处理结束必需释放内存  
  122.     mb->release();  
  123. }  
  124.   
  125. /**********************************************************************************************************************************/  
  126.   
  127. void TaskSoapClient::set_active(bool b)  
  128. {  
  129.     this->active_ = b;  
  130. }  
  131.   
  132. bool TaskSoapClient::get_active()  
  133. {  
  134.     return this->active_;  
  135. }  
  136.   
  137. int TaskSoapClient::process_soap_client_requet(void *soap)  
  138. {  
  139.     int msg_len = sizeof(void *);  
  140.     ACE_Message_Block *mb = NULL;  
  141.   
  142.     ACE_NEW_RETURN(mb, ACE_Message_Block(msg_len+1), -1);  
  143.     ACE_OS::memcpy(mb->wr_ptr(), &soap, msg_len);  
  144.     mb->wr_ptr(msg_len);  
  145.   
  146.     if (this->putq(mb) == -1)  
  147.     {  
  148.         g_logger.error("SOAP Client Requet enqueue to TaskSoapClient failed/n");  
  149.         mb->release();  
  150.         return -1;  
  151.     }  
  152.   
  153.     return 1;  
  154. }  
0 0