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:
- //gsoap ns2 service namespace: http://localhost:9908/ccm_mimport/services.wsdl
- //gsoap ns2 service location: http://localhost:9908/ccm_mimport/services
- typedef char * xsd__string; // encode char * value as the xsd:string schema type
- typedef int xsd__int; // encode xsd__int value as the xsd:int schema typ
- struct ns2__makeCardNotifyReqBean
- {
- xsd__string id_makecard_order;
- xsd__int card_type;
- xsd__string file_name;
- xsd__string start_card_serial;
- xsd__string end_card_serial;
- xsd__int card_count;
- };
- struct ns2__makeCardNotifyRspBean
- {
- xsd__int result; //结果
- xsd__string error_desc; //错误描述
- };
- //卡数据生成结果通知接口
- 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、编写批处理文件:
- echo off
- del *.c *.h *.xml *.nsmap *.cpp
- soapcpp2 -c -S gsoap_server.h
- copy soapC.c ../soapC.cpp
- copy soapServer.c ../soapServer.cpp
- copy soapH.h ../soapH.h
- copy soapStub.h ../soapStub.h
- copy ns2.nsmap ../gsoap_server.nsmap
- echo .
- echo /******************************/
- echo .
- echo 生成的ns2.wsdl必须删除schemaLocation="http://schemas.xmlsoap.org/soap/encoding/"属性
- echo .
- echo /******************************/
- echo .
- pause
4、编写业务实现代码:
- #include <ctype.h>
- #include <string>
- #include <ace/OS.h>
- #include <ace/OS_NS_ctype.h>
- #include <ace/OS_NS_string.h>
- #include "Global_Define.h"
- #include "ffcs_logger.h"
- #include "stdsoap2.h"
- #include "soapH.h"
- #include "gsoap_server.nsmap"
- extern Logger g_logger;
- extern GlobalValue g_val;
- /*-----------------------------------------------------------------------
- * name: 卡数据生成结果通知接口
- * input: soap -- gSOAP运行时环境实例
- * req -- SOAP请求参数
- *
- * output: rsp -- SOAP应答参数
- * return: SOAP_OK -- 成功
- * SOAP_ERR -- 失败:将导致客户端接口调用异常,一般不使用
- *-----------------------------------------------------------------------*/
- SOAP_FMAC5 int SOAP_FMAC6 ns2__makeCardNotify(struct soap* soap, struct ns2__makeCardNotifyReqBean req, struct ns2__makeCardNotifyRspBean *rsp)
- {
- ACE_UINT64 ms_1, ms_2;
- ACE_OS::gettimeofday().msec(ms_1);
- g_logger.debug("*** SOAP请求开始 ***/n");
- if (req.id_makecard_order==NULL || req.file_name==NULL)
- {
- g_logger.error("格式无效/n");
- rsp->result = RET_FORMATERROR;
- rsp->error_desc = "";
- return SOAP_OK;
- }
- rsp->result = RET_SUCCESS;
- rsp->error_desc = "成功";
- ACE_OS::gettimeofday().msec(ms_2);
- g_logger.debug("*** SOAP请求结束,耗时 (%ld)ms ***/n", ms_2-ms_1);
- return SOAP_OK;
- }
5、编写WebService服务端处理代码:
- #include <ace/OS.h>
- #include "stdsoap2.h"
- #include "soapH.h"
- #include "Global_Define.h"
- #include "ffcs_logger.h"
- /************************************************************************/
- /* 全局变量 */
- Logger g_logger;
- GlobalValue g_val;
- /************************************************************************/
- static void * pthr_soap_server_process(void * arg);
- static void * pthr_soap_server_process_task(void * arg);
- int ACE_TMAIN(int argc, ACE_TCHAR* argv[])
- {
- g_val.g_sys_run = 1;
- /*初始化日志系统*/
- g_logger.load_config(CONFIG_FILE);
- g_logger.open_logger();
- /*加载配置参数*/
- if (g_val.load_config(CONFIG_FILE) == -1)
- {
- g_val.g_sys_run = 0;
- g_logger.error("Load config file [%s] fail!/n", CONFIG_FILE);
- ACE_OS::exit();
- return 0;
- }
- /*启动SOAP服务端,方式一*/
- /*
- if (ACE_Thread_Manager::instance()->spawn_n(1,
- (ACE_THR_FUNC)pthr_soap_server_process,//Execute task one
- NULL, //arguments
- THR_NEW_LWP | THR_DETACHED, //New Light Weight Process
- ACE_DEFAULT_THREAD_PRIORITY,
- FFCS_SOAP_SERVER_GRPID)==-1) //Group ID
- g_logger.error("Failure to spawn /"pthr_soap_server_process/" of threads/n");
- */
- /*启动SOAP服务端,方式二*/
- if (ACE_Thread_Manager::instance()->spawn_n(1,
- (ACE_THR_FUNC)pthr_soap_server_process_task,//Execute task one
- NULL, //arguments
- THR_NEW_LWP | THR_DETACHED, //New Light Weight Process
- ACE_DEFAULT_THREAD_PRIORITY,
- FFCS_SOAP_SERVER_GRPID)==-1) //Group ID
- g_logger.error("Failure to spawn /"pthr_soap_server_process_task/" of threads/n");
- while(g_val.g_sys_run == 1)
- {
- ACE_OS::sleep(1);
- }
- return 0;
- }
- /*采用线程池的方式处理SOAP Client请求*/
- static void * pthr_soap_server_process(void * arg)
- {
- char cHost[] = "localhost"; //服务器IP
- int iPort = 9908; //端口
- struct soap soap;
- SOAP_SOCKET m, s;
- int i;
- struct timespec rqt;
- struct soap *soap_thr[MAX_THR]; // 连接池运行时环境实例
- ACE_thread_t tid[MAX_THR]; //线程池标识
- //初始化连接池运行时环境实例
- for (i = 0; i < MAX_THR; i++)
- {
- soap_thr[i] = NULL;
- tid[i] = 0;
- }
- /*初始化服务*/
- soap_init(&soap);
- do
- {
- m = soap_bind(&soap, cHost, iPort, BACKLOG);
- if (!soap_valid_socket(m))
- {
- g_logger.error("Socket bind fail (%d);System retry after 10 seconds/n");
- ACE_OS::sleep(10);
- continue;
- }
- else
- {
- g_logger.debug("Socket %d connection successful %s on port %d/n", m, cHost, iPort);
- break;
- }
- } while (g_val.g_sys_run == 1);
- /*处理请求*/
- while (g_val.g_sys_run == 1)
- {
- for (i = 0; i < MAX_THR; i++)
- {
- s = soap_accept(&soap);
- if (!soap_valid_socket(s))
- {
- if (soap.errnum)
- {
- g_logger.error("SOAP异常:%d/n", soap.errnum);
- continue; // retry
- }
- else
- {
- g_logger.error("Server timed out/n");
- break;
- }
- }
- 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);
- if (!soap_thr[i]) // 首次连接
- {
- soap_thr[i] = soap_copy(&soap);
- if (!soap_thr[i])
- {
- g_logger.error("系统异常/n");
- break;
- }
- }
- else // 循环连接,等待连接池释放资源
- {
- ACE_Thread_Manager::instance()->join(tid[i]);
- g_logger.debug("OLD Thread %d completed/n", i);
- soap_destroy(soap_thr[i]);
- soap_end(soap_thr[i]);
- }
- soap_thr[i]->socket = s;
- //设置编码UTF-8
- soap_set_imode(soap_thr[i], SOAP_C_UTFSTRING);
- /*处理SOAP请求*/
- tid[i] = ACE_Thread_Manager::instance()->spawn_n(1,
- (ACE_THR_FUNC)soap_serve,//Execute task one
- (void*)soap_thr[i], //arguments
- THR_NEW_LWP | THR_JOINABLE, //New Light Weight Process
- ACE_DEFAULT_THREAD_PRIORITY,
- FFCS_SOAP_SERVER_GRPID);
- if (tid[i] == -1) g_logger.error("Failure to spawn /"soap_serve/" of threads/n");
- }
- rqt.tv_sec = 0;
- rqt.tv_nsec = 10000000;
- ACE_OS::nanosleep(&rqt);
- }
- //释放资源
- for (i = 0; i < MAX_THR; i++)
- {
- if (soap_thr[i])
- {
- soap_free(soap_thr[i]); // == soap_done(soap_thr[i]); + free(soap_thr[i]);
- }
- }
- soap_done(&soap);
- return 0;
- }
- /*采用线程池+消息队列的方式处理SOAP Client请求*/
- static void * pthr_soap_server_process_task(void * arg)
- {
- char cHost[] = "localhost"; //服务器IP
- int iPort = 9908; //端口
- struct soap soap;
- struct soap *pSoap;
- SOAP_SOCKET m, s;
- struct timespec rqt;
- TaskSoapClient task_soap_client;
- /*初始化服务*/
- soap_init(&soap);
- do
- {
- m = soap_bind(&soap, cHost, iPort, BACKLOG);
- if (!soap_valid_socket(m))
- {
- g_logger.error("Socket bind fail (%d);System retry after 10 seconds/n");
- ACE_OS::sleep(10);
- continue;
- }
- else
- {
- g_logger.debug("Socket %d connection successful %s on port %d/n", m, cHost, iPort);
- break;
- }
- } while (g_val.g_sys_run == 1);
- /*创建消息处理ACE_Task*/
- task_soap_client.set_active(true);
- if (task_soap_client.activate(THR_NEW_LWP | THR_JOINABLE, TASK_SOAP_CLIENT_POOL_SIZE) == -1)
- {
- g_logger.error("TaskSoapClient activate failed/n");
- return 0;
- }
- /*处理请求*/
- while (g_val.g_sys_run == 1)
- {
- s = soap_accept(&soap);
- if (!soap_valid_socket(s))
- {
- if (soap.errnum)
- {
- g_logger.error("SOAP异常:%d/n", soap.errnum);
- continue; // retry
- }
- else
- {
- g_logger.error("Server timed out/n");
- break;
- }
- }
- 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);
- pSoap = soap_copy(&soap);
- if (!pSoap)
- {
- g_logger.error("系统异常/n");
- continue;
- }
- pSoap->socket = s;
- //设置编码UTF-8
- soap_set_imode(pSoap, SOAP_C_UTFSTRING);
- /*放入队列*/
- task_soap_client.process_soap_client_requet((void *)pSoap);
- rqt.tv_sec = 0;
- rqt.tv_nsec = 50000000;
- ACE_OS::nanosleep(&rqt);
- }
- soap_done(&soap);
- task_soap_client.set_active(false);
- task_soap_client.msg_queue()->close();
- task_soap_client.wait();
- return 0;
- }
6、如果采用线程池+消息队列的方式处理SOAP Client请求,需要引入ACE_Task,并采用ACE_Message_Block实现对了操作:
- /********************************************************************************************
- * huangjf 2009年12月 于福州
- ********************************************************************************************/
- #include <ace/OS.h>
- #include "Global_Define.h"
- #include "ffcs_logger.h"
- #include "ffcs_common.h"
- #include "stdsoap2.h"
- #include "soapH.h"
- extern Logger g_logger;
- /********************************************************************************************
- * WebService Client Requet 处理类
- ********************************************************************************************/
- class TaskSoapClient: public ACE_Task<ACE_MT_SYNCH>
- {
- public:
- TaskSoapClient() : active_(false)
- {
- this->active_ = false;
- this->msg_queue()->high_water_mark(SOAP_HIGHT_MARK);
- ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) TaskSoapClient start/n")));
- }
- virtual ~TaskSoapClient()
- {
- this->active_ = false;
- this->msg_queue()->close();
- ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) TaskSoapClient stop/n")));
- }
- virtual int svc(void);
- bool get_active();
- void set_active(bool b);
- int process_soap_client_requet(void *soap);
- private:
- bool active_;
- void process_soap(ACE_Message_Block *mb = NULL);
- };
- //处理接收队列
- int TaskSoapClient::svc(void)
- {
- g_logger.debug("TaskSoapClient::svc() start/n");
- while (this->active_==true)
- {
- ACE_Message_Block *mb = NULL;
- if (this->getq(mb) == -1)
- {
- /*g_logger.error("取接收队列数据失败/n");*/
- continue;
- }
- process_soap(mb);
- }
- g_logger.debug("TaskSoapClient::svc() stop/n");
- return 0;
- }
- void TaskSoapClient::process_soap(ACE_Message_Block *mb)
- {
- char * data = mb->rd_ptr();
- size_t data_size = mb->length();
- /*g_logger.dump(data, data_size, 1);*/
- /****************************************************************
- * TODO 处理接收到的SOAP Client Request,数据的起始地址为data,长度为data_size
- *****************************************************************/
- struct soap * pSoap = NULL;
- try
- {
- ACE_OS::memcpy(&pSoap, data, MIN(data_size, sizeof(void *)));
- }
- catch (...)
- {
- g_logger.error("struct soap * 转换异常/n");
- return;
- }
- if (pSoap)
- {
- if (!soap_valid_socket(pSoap->socket))
- {
- if (pSoap->errnum)
- {
- g_logger.error("SOAP异常:%d/n", pSoap->errnum);
- }
- else
- {
- g_logger.error("SOAP异常:??/n");
- }
- soap_free(pSoap);/*销毁*/
- return;
- }
- soap_serve(pSoap); /*执行*/
- soap_destroy(pSoap); /*释放*/
- soap_end(pSoap); /*释放*/
- soap_free(pSoap); /*销毁*/
- }
- //数据处理结束必需释放内存
- mb->release();
- }
- /**********************************************************************************************************************************/
- void TaskSoapClient::set_active(bool b)
- {
- this->active_ = b;
- }
- bool TaskSoapClient::get_active()
- {
- return this->active_;
- }
- int TaskSoapClient::process_soap_client_requet(void *soap)
- {
- int msg_len = sizeof(void *);
- ACE_Message_Block *mb = NULL;
- ACE_NEW_RETURN(mb, ACE_Message_Block(msg_len+1), -1);
- ACE_OS::memcpy(mb->wr_ptr(), &soap, msg_len);
- mb->wr_ptr(msg_len);
- if (this->putq(mb) == -1)
- {
- g_logger.error("SOAP Client Requet enqueue to TaskSoapClient failed/n");
- mb->release();
- return -1;
- }
- return 1;
- }