• [转贴]gsoap使用心得!


    最近换了个工作环境,现在在大望路这边上班,呵,刚上班接到的任务就是熟悉gsoap!废话少说,现在开始gSoap学习!

    gSOAP是一个夸平台的,用于开发Web Service服务端和客户端的工具,在WindowsLinuxMAC OSUNIX下使用CC++语言编码,集合了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://blog.chinaunix.net/u1/55091/showart_430965.html
    纯c gSoap实现WebService            http://hi.baidu.com/2sky2sea/blog/item/40ec5555680279c1b745ae9b.html 


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

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

    1//gsoap ns service name: add
    2//gsoap ns service namespace: http://localhost/add.wsdl
    3//gsoap ns service location: http://localhost
    4//gsoap ns service executable: add.cgi
    5//gsoap ns service encoding: encoded
    6//gsoap ns schema namespace: urn:add
    7
    8int ns__add( int num1, int num2, int* sum );
    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主程序:

    #include "add.h"
    #include 
    "add.nsmap"

    int main(int argc, char* argv[])
    {
        
        
    int m, s; /* master and slave sockets */
        
    struct soap add_soap;
        soap_init(
    &add_soap);
        
    //soap_set_namespaces(&add_soap, add_namespaces);
        
        
    if (argc < 2)
        
    {
            printf(
    "usage: %s <server_port>  ", argv[0]);
            exit(
    1);
        }

        
    else
        

            m 
    = soap_bind(&add_soap, NULL, atoi(argv[1]), 100);
            
    if (m < 0)
            
    {
                soap_print_fault(
    &add_soap, stderr);
                exit(
    -1);
            }

            
            fprintf(stderr, 
    "Socket connection successful: master socket = %d ", m);
            
    for ( ; ; )
            

                s 
    = soap_accept(&add_soap); 
                
    if (s < 0)
                

                    soap_print_fault(
    &add_soap, stderr);
                    exit(
    -1);
                }

                fprintf(stderr, 
    "Socket connection successful: slave socket = %d ", s);
                
                soap_serve(
    &add_soap);//该句说明该server的服务
                soap_end(&add_soap);
            }

        }

        
    return 0;
    }

    //server端的实现函数与add.h中声明的函数相同,但是多了一个当前的soap连接的参数
    int ns__add(struct soap *add_soap, int num1, int num2, int *sum)
    {
        
    *sum = num1 + num2;
        
    return 0;
    }


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

    二 对应的客户端
    1。客户端程序代码如下:

    #include <stdio.h>
    #include 
    <stdlib.h>
    #include 
    "soapH.h"
    #include 
    "add.nsmap"


    int add(const char* server, int num1, int num2, int *sum);

    int main(int argc, char **argv) 
    {
        
    int result = -1;
        
    char* server="http://localhost:4567";
        
    int num1 = 0;
        
    int num2 = 0;
        
    int sum = 0;
        
    if( argc < 3 )
        
    {
            printf(
    "usage: %s num1 num2  ", argv[0]);
            exit(
    0);
        }

        
        num1 
    = atoi(argv[1]);
        num2 
    = atoi(argv[2]);
        
        result 
    = add(server, num1, num2, &sum);
        
    if (result != 0)
        
    {
            printf(
    "soap err,errcode = %d ", result);
        }

        
    else
        
    {
            printf(
    "%d+%d=%d ", num1, num2, sum );
        }

        
    return 0;
    }


    int add( const char* server, int num1, int num2, int *sum )
    {
        
    struct soap add_soap;
        
    int result = 0;
        soap_init(
    &add_soap);
    //    soap_set_namespaces(&add_soap, add_namespaces);
        
        
    //该函数是客户端调用的主要函数,后面几个参数和add.h中声明的一样,前面多了3个参数,函数名是接口函数名ns__add前面加上soap_call_
        soap_call_ns__add( &add_soap, server, "", num1, num2, sum );
        
    if(add_soap.error)
        
    {
            printf(
    "soap error:%d,%s,%s ", add_soap.error, *soap_faultcode(&add_soap), *soap_faultstring(&add_soap) );
            result 
    = add_soap.error;
        }
     
        soap_end(
    &add_soap);
        soap_done(
    &add_soap);
        
    return result;
    }


    2.客户端程序既可以新建一个新的win32控制台程序,将刚才生成的nsmap,soapH.h,soapClient.h等文件加入工程,编 译既可。我是直接在原先工程中加入一客户端代码,将webserver.cpp文件移除,并且将soapServer.cpp等server端需要的文件 移除,将soapClient.cpp等client端需要的cpp添加到工程,编译既可。
    3.启动server程序,F5客户端程序,经测试正常。

    三 遇到的问题
    1.server端可以编译成CGI方式执行,而并不是绑定到某个端口,这种方式我没有实践。

    if (argc < 2// no args: assume this is a CGI application 
       
          soap_serve(
    &soap); // serve request, one thread, CGI style 
          soap_destroy(&soap); // dealloc C++ data 
          soap_end(&soap); // dealloc data and clean up 
    }

    2.在编译服务器及客户端程序时一开始对add.h生成的文件添加到工程,经常出现问题,需要自己不调试。特别是链接时段,server/client要 与其生成的文件相对应,server调用生成的soapserver.cpp,client调用生成的soapclient.cpp文件。
    3.多线程方式,在windows下建议用pthread_win32库,这里给出多线程下的例子。
    一 gSOAP需要的头文件:

    //gsoap ns service name: calc
    //gsoap ns service style: rpc
    //gsoap ns service encoding: encoded
    //gsoap ns service namespace: http://127.0.0.1:8089/calc.wsdl
    //gsoap ns service location: http://127.0.0.1:8089/cal
    //gsoap ns schema  namespace:    urn:calc
    int ns__add(double a, double b, double *result);
    int ns__sub(double a, double b, double *result);
    int ns__mul(double a, double b, double *result);
    int ns__div(double a, double b, double *result);
    int ns__pow(double a, double b, double *result);

    二 多线程服务器关键代码

    #include 
    #include  
    "calc.nsmap"
    #include  
    "soapH.h"

    /////////////////////////////////////////////////////////////////////////
    ///宏与全局变量的定义

    #define  BACKLOG (100)  
    #define  MAX_THR (10)   
    #define  MAX_QUEUE (1000)


    pthread_mutex_t queue_cs;                        
    //队列锁
    pthread_cond_t  queue_cv;                          //条件变量
    SOAP_SOCKET     queue[MAX_QUEUE];   //数组队列
    int                           head =0, tail =0;          //队列头队列尾初始化         
    //////////////////////////////////////////////////////////////////////////


    //////////////////////////////////////////////////////////////////////////

    void *      process_queue(void *);        //线程入口函数
    int         enqueue(SOAP_SOCKET);  //入队列函数
    SOAP_SOCKET dequeue(void);         //出队列函数

    //////////////////////////////////////////////////////////////////////////
    //线程入口函数
    void * process_queue(void * soap)
    {
      
    struct soap * tsoap = (struct soap *)soap;
      
    for(;;)
      
    {
            tsoap
    ->socket = dequeue();
            
    if (!soap_valid_socket(tsoap->socket))
           
    {
             
    break;
            }

            soap_serve(tsoap);
            soap_destroy(tsoap);
            soap_end(tsoap);
      }

      
    return NULL;
    }


    //入队列操作
    int enqueue(SOAP_SOCKET sock)
    {
      
    int status = SOAP_OK;
      
    int next;
      pthread_mutex_lock(
    &queue_cs);
      next 
    = tail +1;
      
    if (next >= MAX_QUEUE) 
        next 
    = 0;
      
    if (next == head) 
          status 
    = SOAP_EOM;
      
    else
      
    {
        queue[tail] 
    =sock;
        tail 
    = next;
      }

      pthread_cond_signal(
    &queue_cv);
      pthread_mutex_unlock(
    &queue_cs);
      
    return status;
    }


    //出队列操作
    SOAP_SOCKET dequeue()
    {
      SOAP_SOCKET sock;
      pthread_mutex_lock(
    &queue_cs);
       
    while (head == tail )
       
    {
              pthread_cond_wait(
    &queue_cv,&queue_cs);
       }

      sock 
    = queue[head++];
      
    if (head >= MAX_QUEUE)
            
    {
        head 
    =0;
      }

      pthread_mutex_unlock(
    &queue_cs);
      
    return sock;
    }



    //////////////////////////具体服务方法////////////////////////////////////////
    //加法的实现
    int ns__add(struct soap *soap, double a, double b, double *result)
    {
          
    *result = a + b;
          
    return SOAP_OK;
    }
     
    //减法的实现
    int ns__sub(struct soap *soap, double a, double b, double *result)

         
    *result = a - b;
         
    return SOAP_OK;
    }
     
    //乘法的实现
    int ns__mul(struct soap *soap, double a, double b, double *result)

         
    *result = a * b;
         
    return SOAP_OK;
    }
     
    //除法的实现
    int ns__div(struct soap *soap, double a, double b, double *result)

       
    if (b)
           
    *result = a / b;
       
    else
      
    {
             
    char *= (char*)soap_malloc(soap, 1024);
             sprintf(s, 
    "Can't">http://tempuri.org/">Can't divide %f by %f", a, b);
             return soap_sender_fault(soap, "Division by zero", s);
      }

      
    return SOAP_OK;
    }
     
    //乘方的实现
    int ns__pow(struct soap *soap, double a, double b, double *result)

      
    *result = pow(a, b);
      
    if (soap_errno == EDOM) /* soap_errno 和errorno类似, 但是和widnows兼容 */
      

        
    char *= (char*)soap_malloc(soap, 1024);
        sprintf(s, 
    "Can't take the power of %f to  %f", a, b);
        sprintf(s, 
    "Can't">http://tempuri.org/">Can't take power of %f to %f", a, b);
        return soap_sender_fault(soap, "Power function domain error", s);
      }

      
    return SOAP_OK;
    }
     

    //////////////////////////////////////////////////////////////////////////////////////////////////////
    //主函数
    int main(int argc,char ** argv)
    {
      
    struct soap ServerSoap;
         
    //初始话运行时环境
        soap_init(&ServerSoap);
        
    //如果没有参数,当作CGI程序处理
        if (argc <2
        
    {       
               
    //CGI 风格服务请求,单线程
              soap_serve(&ServerSoap);
              
    //清除序列化的类的实例
             soap_destroy(&ServerSoap);
             
    //清除序列化的数据
            soap_end(&ServerSoap);     
       }
    else
       
    {
         
    struct soap * soap_thr[MAX_THR];
         pthread_t tid[MAX_THR];
         
    int i,port = atoi(argv[1]);
         SOAP_SOCKET m,s;
          
    //锁和条件变量初始化
         pthread_mutex_init(&queue_cs,NULL);
         pthread_cond_init(
    &queue_cv,NULL);
         
    //绑定服务端口
        m = soap_bind(&ServerSoap,NULL,port,BACKLOG);
        
    //循环直至服务套接字合法
        while (!soap_valid_socket(m))
       
    {
                    fprintf(stderr,
    "Bind port error! ");
                    m 
    = soap_bind(&ServerSoap,NULL,port,BACKLOG);
        }

        fprintf(stderr,
    "socket connection successful %d ",m);
                    
         
    //生成服务线程
        for(i = 0; i <MAX_THR; i++)

       
    {
          soap_thr[i] 
    = soap_copy(&ServerSoap);
          fprintf(stderr,
    "Starting thread %d ",i);
          pthread_create(
    &tid[i],NULL,(void*(*)(void*))process_queue,(void*)soap_thr[i]);
        }

                    
        
    for(;;)
        
    {
          
    //接受客户端的连接
          s = soap_accept(&ServerSoap);
          
    if (!soap_valid_socket(s)) 
          
    {
            
    if (ServerSoap.errnum) 
                                    
    {
              soap_print_fault(
    &ServerSoap,stderr);
              
    continue;
            }
    else
            
    {
              fprintf(stderr,
    "Server timed out ");
              
    break;
            }

          }

           
    //客户端的IP地址
          fprintf(stderr,"Accepted connection from IP= %d.%d.%d.%d socket = %d ",
                                   ((ServerSoap.ip)
    >>24)&&0xFF,((ServerSoap.ip)>>16)&0xFF,((ServerSoap.ip)>>8)&0xFF,(ServerSoap.ip)&0xFF,(ServerSoap.socket));
          
    //请求的套接字进入队列,如果队列已满则循环等待
           while(enqueue(s) == SOAP_EOM)
                    Sleep(
    1000);
        }

        
    //服务结束后的清理工作
        for(i = 0; i < MAX_THR; i++)
        
    {
          
    while (enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM) 
           
    {
               Sleep(
    1000);
          }

        }

        
    for(i=0; i< MAX_THR; i++)
        
    {
          fprintf(stderr,
    "Waiting for thread %d to terminate ..",i);
          pthread_join(tid[i],NULL);
          fprintf(stderr,
    "terminated ");
          soap_done(soap_thr[i]);
          free(soap_thr[i]);
        }

        pthread_mutex_destroy(
    &queue_cs);
        pthread_cond_destroy(
    &queue_cv);
      }

        
    //分离运行时的环境
      soap_done(&ServerSoap);
      
    return 0;
    }

  • 相关阅读:
    实验 1:Mininet 源码安装和可视化拓扑工具
    Linux bond 网卡主备模式配置
    git常用命令总结
    框架搭建之--配置去除用户输入两边的空格
    性能优化之--数据库缓存
    性能优化之缓存--文件缓存
    网站优化之缓存--页面缓存
    网站优化之缓存--session和cache以及常用缓存应用之间的区别
    MVC请求管道详细总结梳理。
    sql优化记录
  • 原文地址:https://www.cnblogs.com/redmondfan/p/3182001.html
Copyright © 2020-2023  润新知