gSOAP使用心得

本文介绍如何使用gSOAP在Windows平台上构建WebService服务端和客户端。详细步骤包括创建服务接口、生成代码、配置工程以及调试程序。此外,还提供了一个简单的加法函数作为示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

gSOAP是一个夸平台的,用于开发Web Service服务端和客户端的工具,在Windows、Linux、MAC OS和UNIX下使用C和C++语言编码,集合了SSL功能。

下载地址:http://sourceforge.net/projects/gsoap2

官方网站:http://genivia.com/Products/gsoap/index.html

对于Windows平台下开发客户端,首先下载最新的gsoap_win32_2.7.6c.zip包,具体在以下地址:http://optusnet.dl.sourceforge.net/sourceforge/gsoap2/gsoap_win32_2.7.6c.zip

首先查看gsoap的User's Guide,基本就能对gsoap有个全面的了解,通过阅读Sample里的例子程序深入。然后搜索网上其它一些文章,比如:
gSOAP简单多线程服务器程序 http://wenku.baidu.com/view/c0a58e4ce45c3b3567ec8bd5.html

纯c gSoap实现WebService            http://hi.baidu.com/2sky2sea/item/1b791c4a8b6660eda4c06664

接下来我结合自己的实践与理解,讲讲VC用gsoap下编写webService和客户端程序,有不对的地方还请大家指正,谢谢。
我以网上出现的实现一个简单的加法函数为例,讲讲我在操作过程中遇到的问题。

一 服务器端
1.首先编写 add.h文件:

[cpp]  view plain  copy
  1. 1//gsoap ns service name: add  
  2. 2//gsoap ns service namespace: http://localhost/add.wsdl  
  3. 3//gsoap ns service location: http://localhost  
  4. 4//gsoap ns service executable: add.cgi  
  5. 5//gsoap ns service encoding: encoded  
  6. 6//gsoap ns schema namespace: urn:add  
  7. 7  
  8. 8int ns__add( int num1, int num2, int* sum );  
  9. 9  
2.用gsoap/bin目录下的soapcpp2.exe程序,生成一些文件。可以把soapcpp2.exe拷贝到一add.h目录下,用cmd执行soapcpp2.exe add.h就可以,在这个目录下会自动生成许多将来有用的文件,如add.namap,soapH.h,soapC.cpp,soapClient.cpp,soapServer.cpp等文件。soapcpp2.exe可以带参数执行,具体执行soapcpp2.exe -h查看。

3.新建一个win32控制台工程,加入wsock32.lib库,将刚才生成的那些文件添加到工程中。然后编写webserver.cpp主程序:
[cpp]  view plain  copy
  1. #include "add.h"  
  2. #include "add.nsmap"  
  3.   
  4. int main(int argc, char* argv[])  
  5. {  
  6.       
  7.     int m, s; /* master and slave sockets */  
  8.     struct soap add_soap;  
  9.     soap_init(&add_soap);  
  10.     //soap_set_namespaces(&add_soap, add_namespaces);  
  11.       
  12.     if (argc < 2)  
  13.     {  
  14.         printf("usage: %s <server_port> \n", argv[0]);  
  15.         exit(1);  
  16.     }  
  17.     else  
  18.     {   
  19.         m = soap_bind(&add_soap, NULL, atoi(argv[1]), 100);  
  20.         if (m < 0)  
  21.         {  
  22.             soap_print_fault(&add_soap, stderr);  
  23.             exit(-1);  
  24.         }  
  25.           
  26.         fprintf(stderr, "Socket connection successful: master socket = %d\n", m);  
  27.         for ( ; ; )  
  28.         {   
  29.             s = soap_accept(&add_soap);   
  30.             if (s < 0)  
  31.             {   
  32.                 soap_print_fault(&add_soap, stderr);  
  33.                 exit(-1);  
  34.             }  
  35.             fprintf(stderr, "Socket connection successful: slave socket = %d\n", s);  
  36.               
  37.             soap_serve(&add_soap);//该句说明该server的服务  
  38.             soap_end(&add_soap);  
  39.         }  
  40.     }  
  41.     return 0;  
  42. }  
  43. //server端的实现函数与add.h中声明的函数相同,但是多了一个当前的soap连接的参数  
  44. int ns__add(struct soap *add_soap, int num1, int num2, int *sum)  
  45. {  
  46.     *sum = num1 + num2;  
  47.     return 0;  
  48. }  

4. 编译这个程序,会提示错误,将gsoap_win32目录下stdsoap2.cpp,stdsoap2.h文件加入工程,重新编译如果还有错误,可能是你将add.h生成的文件添加入工程出错的原因。实际上在编写server程序时,无须带Client的那些文件,还有带Lib的文件也无须添加到工程中。再重新编译应该就没有问题了,启动4567端口,在ie中输入localhost:4567,如果显示xml页面,说明程序已经启动。

二 对应的客户端

1。客户端程序代码如下:

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include "soapH.h"  
  4. #include "add.nsmap"  
  5.   
  6.   
  7. int add(const char* server, int num1, int num2, int *sum);  
  8.   
  9. int main(int argc, char **argv)   
  10. {  
  11.     int result = -1;  
  12.     char* server="http://localhost:4567";  
  13.     int num1 = 0;  
  14.     int num2 = 0;  
  15.     int sum = 0;  
  16.     if( argc < 3 )  
  17.     {  
  18.         printf("usage: %s num1 num2 \n", argv[0]);  
  19.         exit(0);  
  20.     }  
  21.       
  22.     num1 = atoi(argv[1]);  
  23.     num2 = atoi(argv[2]);  
  24.       
  25.     result = add(server, num1, num2, &sum);  
  26.     if (result != 0)  
  27.     {  
  28.         printf("soap err,errcode = %d\n", result);  
  29.     }  
  30.     else  
  31.     {  
  32.         printf("%d+%d=%d\n", num1, num2, sum );  
  33.     }  
  34.     return 0;  
  35. }  
  36.   
  37. int add( const char* server, int num1, int num2, int *sum )  
  38. {  
  39.     struct soap add_soap;  
  40.     int result = 0;  
  41.     soap_init(&add_soap);  
  42. //    soap_set_namespaces(&add_soap, add_namespaces);  
  43.       
  44.     //该函数是客户端调用的主要函数,后面几个参数和add.h中声明的一样,前面多了3个参数,函数名是接口函数名ns__add前面加上soap_call_  
  45.     soap_call_ns__add( &add_soap, server, "", num1, num2, sum );  
  46.     if(add_soap.error)  
  47.     {  
  48.         printf("soap error:%d,%s,%s\n", add_soap.error, *soap_faultcode(&add_soap), *soap_faultstring(&add_soap) );  
  49.         result = add_soap.error;  
  50.     }   
  51.     soap_end(&add_soap);  
  52.     soap_done(&add_soap);  
  53.     return result;  
  54. }  
2.客户端程序既可以新建一个新的win32控制台程序,将刚才生成的nsmap,soapH.h,soapClient.h等文件加入工程,编译既可。我是直接在原先工程中加入一客户端代码,将webserver.cpp文件移除,并且将soapServer.cpp等server端需要的文件移除,将soapClient.cpp等client端需要的cpp添加到工程,编译既可。
3.启动server程序,F5客户端程序,经测试正常。

三 遇到的问题
1.server端可以编译成CGI方式执行,而并不是绑定到某个端口,这种方式我没有实践。
[cpp]  view plain  copy
  1. if (argc < 2) // no args: assume this is a CGI application   
  2.    {   
  3.       soap_serve(&soap); // serve request, one thread, CGI style   
  4.       soap_destroy(&soap); // dealloc C++ data   
  5.       soap_end(&soap); // dealloc data and clean up   
  6. }  

2.在编译服务器及客户端程序时一开始对add.h生成的文件添加到工程,经常出现问题,需要自己不调试。特别是链接时段,server/client要与其生成的文件相对应,server调用生成的soapserver.cpp,client调用生成的soapclient.cpp文件。
3.多线程方式,在windows下建议用pthread_win32库,这里给出多线程下的例子。
一 gSOAP需要的头文件:
[cpp]  view plain  copy
  1. //gsoap ns service name: calc  
  2. //gsoap ns service style: rpc  
  3. //gsoap ns service encoding: encoded  
  4. //gsoap ns service namespace: http://127.0.0.1:8089/calc.wsdl  
  5. //gsoap ns service location: http://127.0.0.1:8089/cal  
  6. //gsoap ns schema  namespace:    urn:calc  
  7. int ns__add(double a, double b, double *result);  
  8. int ns__sub(double a, double b, double *result);  
  9. int ns__mul(double a, double b, double *result);  
  10. int ns__div(double a, double b, double *result);  
  11. int ns__pow(double a, double b, double *result);  
  12.   
  13. 二 多线程服务器关键代码  
  14.   
  15. #include   
  16. #include  "calc.nsmap"  
  17. #include  "soapH.h"  
  18.   
  19. /////////////////////////////////////////////////////////////////////////  
  20. ///宏与全局变量的定义  
  21. #define  BACKLOG (100)    
  22. #define  MAX_THR (10)     
  23. #define  MAX_QUEUE (1000)  
  24.   
  25.   
  26. pthread_mutex_t queue_cs;                        //队列锁  
  27. pthread_cond_t  queue_cv;                          //条件变量  
  28. SOAP_SOCKET     queue[MAX_QUEUE];   //数组队列  
  29. int                           head =0, tail =0;          //队列头队列尾初始化           
  30. //////////////////////////////////////////////////////////////////////////  
  31.   
  32.   
  33. //////////////////////////////////////////////////////////////////////////  
  34. void *      process_queue(void *);        //线程入口函数  
  35. int         enqueue(SOAP_SOCKET);  //入队列函数  
  36. SOAP_SOCKET dequeue(void);         //出队列函数  
  37.   
  38. //////////////////////////////////////////////////////////////////////////  
  39. //线程入口函数  
  40. void * process_queue(void * soap)  
  41. {  
  42.   struct soap * tsoap = (struct soap *)soap;  
  43.   for(;;)  
  44.   {  
  45.         tsoap->socket = dequeue();  
  46.         if (!soap_valid_socket(tsoap->socket))  
  47.        {  
  48.          break;  
  49.         }  
  50.         soap_serve(tsoap);  
  51.         soap_destroy(tsoap);  
  52.         soap_end(tsoap);  
  53.   }  
  54.   return NULL;  
  55. }  
  56.   
  57. //入队列操作  
  58. int enqueue(SOAP_SOCKET sock)  
  59. {  
  60.   int status = SOAP_OK;  
  61.   int next;  
  62.   pthread_mutex_lock(&queue_cs);  
  63.   next = tail +1;  
  64.   if (next >= MAX_QUEUE)   
  65.     next = 0;  
  66.   if (next == head)   
  67.       status = SOAP_EOM;  
  68.   else  
  69.   {  
  70.     queue[tail] =sock;  
  71.     tail = next;  
  72.   }  
  73.   pthread_cond_signal(&queue_cv);  
  74.   pthread_mutex_unlock(&queue_cs);  
  75.   return status;  
  76. }  
  77.   
  78. //出队列操作  
  79. SOAP_SOCKET dequeue()  
  80. {  
  81.   SOAP_SOCKET sock;  
  82.   pthread_mutex_lock(&queue_cs);  
  83.    while (head == tail )  
  84.    {  
  85.           pthread_cond_wait(&queue_cv,&queue_cs);  
  86.    }  
  87.   sock = queue[head++];  
  88.   if (head >= MAX_QUEUE)  
  89.         {  
  90.     head =0;  
  91.   }  
  92.   pthread_mutex_unlock(&queue_cs);  
  93.   return sock;  
  94. }  
  95.   
  96.   
  97. //////////////////////////具体服务方法////////////////////////////////////////  
  98. //加法的实现  
  99. int ns__add(struct soap *soap, double a, double b, double *result)  
  100. {  
  101.       *result = a + b;  
  102.       return SOAP_OK;  
  103. }   
  104. //减法的实现  
  105. int ns__sub(struct soap *soap, double a, double b, double *result)  
  106. {   
  107.      *result = a - b;  
  108.      return SOAP_OK;  
  109. }   
  110. //乘法的实现  
  111. int ns__mul(struct soap *soap, double a, double b, double *result)  
  112. {   
  113.      *result = a * b;  
  114.      return SOAP_OK;  
  115. }   
  116. //除法的实现  
  117. int ns__div(struct soap *soap, double a, double b, double *result)  
  118. {   
  119.    if (b)  
  120.        *result = a / b;  
  121.    else  
  122.   {  
  123.          char *s = (char*)soap_malloc(soap, 1024);  
  124.          sprintf(s, "Can't">http://tempuri.org/">Can't divide %f by %f", a, b);  
  125.          return soap_sender_fault(soap, "Division by zero", s);  
  126.   }  
  127.   return SOAP_OK;  
  128. }   
  129. //乘方的实现  
  130. int ns__pow(struct soap *soap, double a, double b, double *result)  
  131. {   
  132.   *result = pow(a, b);  
  133.   if (soap_errno == EDOM) /* soap_errno 和errorno类似, 但是和widnows兼容 */  
  134.   {   
  135.     char *s = (char*)soap_malloc(soap, 1024);  
  136.     sprintf(s, "Can't take the power of %f to  %f", a, b);  
  137.     sprintf(s, "Can't">http://tempuri.org/">Can't take power of %f to %f", a, b);  
  138.     return soap_sender_fault(soap, "Power function domain error", s);  
  139.   }  
  140.   return SOAP_OK;  
  141. }   
  142.   
  143. //////////////////////////////////////////////////////////////////////////////////////////////////////  
  144. //主函数  
  145. int main(int argc,char ** argv)  
  146. {  
  147.   struct soap ServerSoap;  
  148.      //初始话运行时环境  
  149.     soap_init(&ServerSoap);  
  150.     //如果没有参数,当作CGI程序处理  
  151.     if (argc <2)   
  152.     {         
  153.            //CGI 风格服务请求,单线程  
  154.           soap_serve(&ServerSoap);  
  155.           //清除序列化的类的实例  
  156.          soap_destroy(&ServerSoap);  
  157.          //清除序列化的数据  
  158.         soap_end(&ServerSoap);       
  159.    }else  
  160.    {  
  161.      struct soap * soap_thr[MAX_THR];  
  162.      pthread_t tid[MAX_THR];  
  163.      int i,port = atoi(argv[1]);  
  164.      SOAP_SOCKET m,s;  
  165.       //锁和条件变量初始化  
  166.      pthread_mutex_init(&queue_cs,NULL);  
  167.      pthread_cond_init(&queue_cv,NULL);  
  168.      //绑定服务端口  
  169.     m = soap_bind(&ServerSoap,NULL,port,BACKLOG);  
  170.     //循环直至服务套接字合法  
  171.     while (!soap_valid_socket(m))  
  172.    {  
  173.                 fprintf(stderr,"Bind port error! ");  
  174.                 m = soap_bind(&ServerSoap,NULL,port,BACKLOG);  
  175.     }  
  176.     fprintf(stderr,"socket connection successful %d ",m);  
  177.                   
  178.      //生成服务线程  
  179.     for(i = 0; i <MAX_THR; i++)  
  180.   
  181.    {  
  182.       soap_thr[i] = soap_copy(&ServerSoap);  
  183.       fprintf(stderr,"Starting thread %d ",i);  
  184.       pthread_create(&tid[i],NULL,(void*(*)(void*))process_queue,(void*)soap_thr[i]);  
  185.     }  
  186.                   
  187.     for(;;)  
  188.     {  
  189.       //接受客户端的连接  
  190.       s = soap_accept(&ServerSoap);  
  191.       if (!soap_valid_socket(s))   
  192.       {  
  193.         if (ServerSoap.errnum)   
  194.                                 {  
  195.           soap_print_fault(&ServerSoap,stderr);  
  196.           continue;  
  197.         }else  
  198.         {  
  199.           fprintf(stderr,"Server timed out ");  
  200.           break;  
  201.         }  
  202.       }  
  203.        //客户端的IP地址  
  204.       fprintf(stderr,"Accepted connection from IP= %d.%d.%d.%d socket = %d ",  
  205.                                ((ServerSoap.ip)>>24)&&0xFF,((ServerSoap.ip)>>16)&0xFF,((ServerSoap.ip)>>8)&0xFF,(ServerSoap.ip)&0xFF,(ServerSoap.socket));  
  206.       //请求的套接字进入队列,如果队列已满则循环等待  
  207.        while(enqueue(s) == SOAP_EOM)  
  208.                 Sleep(1000);  
  209.     }  
  210.     //服务结束后的清理工作  
  211.     for(i = 0; i < MAX_THR; i++)  
  212.     {  
  213.       while (enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM)   
  214.        {  
  215.            Sleep(1000);  
  216.       }  
  217.     }  
  218.     for(i=0; i< MAX_THR; i++)  
  219.     {  
  220.       fprintf(stderr,"Waiting for thread %d to terminate ..",i);  
  221.       pthread_join(tid[i],NULL);  
  222.       fprintf(stderr,"terminated ");  
  223.       soap_done(soap_thr[i]);  
  224.       free(soap_thr[i]);  
  225.     }  
  226.     pthread_mutex_destroy(&queue_cs);  
  227.     pthread_cond_destroy(&queue_cv);  
  228.   }  
  229.     //分离运行时的环境  
  230.   soap_done(&ServerSoap);  
  231.   return 0;  
  232. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值