gSoap使用笔记

(基于gsoap-win32-2.7版本,编译环境为VS2005)

客户端

访问自己定义的一个WebService(命名为AddService,对输入的两个整形参数求和,具体服务定义参见 AddService.wsdl)

转换WSDL

wsdl2h.exe -s -o AddService.h AddService.wsdl

生成具体调用代码

在命令行输入soapcpp2.exe -C AddService.h

生成代码后,AddService.h就没有用了,不用加入到工程中。

生成的文件
  • soapStub.h
  • soapAddServiceSoapBindingProxy.h:封装了调用webservice的类
  • soapH.h
  • soapClientLib.cpp:用不到
  • soapClient.cpp
  • soapC.cpp
  • AddServiceSoapBinding.nsmap:namespaces声明,需要包含在一个cpp文件里面,比如放在 StdAfx.cpp里面,否则连接时报错:unresolved external symbol _namespaces

还需要stdsoap2.cpp和stdsoap2.h文件,在gsoap-2.7soapcpp2目录下。

注意:#include “StdAfx.h”加到第一行,否则VC编译报错:fatal error C1010: unexpected end of file while looking for precompiled header directive

实际调用代码

将这些文件加入到C++工程中,可以使用以下代码调用WebService:

  • 头文件
    <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> //  包含代理类的头文件
    #include  " gSoap\soapAddBindingProxy.h "
  • 声明访问代理对象
    <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> AddBinding serviceBinding;
  • 设置访问的WebServiceURL
    <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> serviceBinding.endpoint  =  ( " http://LocalHost:8082/ " );
  • 调用接口
    <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> int  iResult;
    nRetCode 
    =  serviceBinding.__ns1__AddOperation( 12 22 ,iResult);

服务端

实现AddService(对输入的两个整形参数求和)

生成调用代码

同客户端生成方法基本一致。需要注意的是以下几点:

  • 由.h文件生成具体调用代码:soapcpp2.exe -S AddService.h
  • soapClient.cpp soapClientLib.cpp soapServerLib.cpp这三个文件不需要加入到C++工程中。
实现服务线程
  • 在程序开始时,启动服务线程。
    <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> UINT GSoapServiceThreadFunc(LPVOID p)
    {
    ...
    }
  • 定义编码格式
    <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> //  设置UTF-8编码方式
    soap_set_mode( & soap, SOAP_C_UTFSTRING);
  • 设置服务的端口号
    代码
    <!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> //  端口号
    int  port  =   8083 ;
    int  backlog  =   100 //
    int  m  =  soap_bind( & soap, NULL, port, backlog);
    if (m  <   0 )
    {
            strOutput.Format(_T(
    " GSoapServiceThreadFunc——在端口%d上启动服务失败! " ), port);
            OutputDebugString(strOutput);
            soap_done(
    & soap);  //  close master socket and detach environment
            exit( - 1 );
    }


  • 设置超时
    <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> soap.accept_timeout  =   5 ; //  设置GSoap连接超时,单位:秒
  • 创建循环,监听,如果有新连接进来则创建请求处理现场
    代码
    <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> while (TRUE)
    {
        
    if ( WaitForSingleObject(g_eventTerminateService.m_hObject,  0 ==  WAIT_OBJECT_0 )
        
    //  结束GSoap服务线程
        {
            
    break ;
        }
        
    int  s  =  soap_accept( & soap);
        
    if ! soap_valid_socket(s) )
        {
            
    if ( soap.errnum )
            {
                soap_print_fault(
    & soap, stderr);
                soap_done(
    & soap);  //  close master socket and detach environment
                exit( 1 );
            }
            
            strOutput.Format(_T(
    " \nGSoapServiceThreadFunc——等待客户端连接超时! " ));
            OutputDebugString(strOutput);
        }
        
    else
        {
            strOutput.Format(_T(
    " \n收到来自于IP地址%d.%d.%d.%d的socket连接%d! " ), (soap.ip  >>   24 ) & 0xFF , (soap.ip  >>   16 ) & 0xFF , (soap.ip  >>   8 ) & 0xFF , soap.ip & 0xFF , s);
            OutputDebugString(strOutput);
            
    struct  soap *  tsoap  =  soap_copy( & soap);  //  make a safe copy
            
            
    if ! tsoap )
            {
                
    break ;
            }
            
            AfxBeginThread(process_request, tsoap);
        }
    }


实现请求处理线程
相应代码
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> ///  GSoap请求处理线程
UINT process_request(LPVOID soap)
{
    CoInitialize(NULL);

    soap_serve((
struct  soap * )soap);      //  会自动调用具体的接口函数
    soap_destroy(( struct  soap * )soap);        //  dealloc C++ data
    soap_end(( struct  soap * )soap);            //  dealloc data and clean up
    soap_done(( struct  soap * )soap);           //  detach soap struct
    free(soap);

    CoUninitialize();

    
return   0 ;
}
实现接口功能函数
在代码中定义相应的接口功能函数
<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> int  __ns1__AddOperation( struct  soap * int  A,  int  B,  int   & result)
{
    result 
=  A  +  B;
    
return  SOAP_OK;
}

 

函数原型在soapStub.h中定义


代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> /* *****************************************************************************\
 *                                                                            *
 * Service Operations                                                         *
 *                                                                            *
\*****************************************************************************
*/

SOAP_FMAC5 
int  SOAP_FMAC6 __ns1__AddOperation( struct  soap * int  A,  int  B,  int   & result);


现在采用的是默认的命名空间前缀,可以使用typemap.dat文件赋予自定义的命名空间。

常见问题

支持访问wsdl
  • 首先要设置回调处理函数
    <!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> soap.fget  =  http_get;
    soap.fpost 
    =  http_post;
  • 两个回调函数的接口定义(stdsoap2.h)
    <!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> int  ( * fpost)( struct  soap * const   char * const   char * int const   char * const   char * , size_t);
    int  ( * fget)( struct  soap * );
  • 根据接口定义实现相应的函数
    代码
    <!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> int  http_post( struct  soap  * soap,  const   char   * endpoint,  const   char   * host,  int  port, const   char   * path,  const   char   * action, size_t count)
    {
            
    return  http_get( soap );  //  简单处理,直接调用http_get
    }

    int  http_get( struct  soap  * soap)
    {
            ...
    }
  • 在http_get函数中解析外部访问路径,并且获取相应的wsdl文件名
    代码
    <!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> //  请求WSDL时,传送相应文件
    //  获取请求的wsdl文件名
    string  fielPath(soap -> path);
    size_t pos 
    =  fielPath.rfind( " / " );
    string  fileName(fielPath, pos + 1 );

    //  将?替换为.
    size_t dotPos  =  fileName.rfind( " ? " );

    if (dotPos  ==   - 1 )
    {
            
    //  未找到
             return   404 ;
    }

    fileName.replace(dotPos,
    1 " . " );
  • 打开WSDL文件发送到客户端
    代码
    <!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> //  打开WSDL文件准备拷贝
    FILE *  fd  =  fopen(fileName.c_str(),  " rb " );
    if  ( ! fd)
    {
        
    //  return HTTP not found error
         return   404 ;
    }

    //  HTTP header with text/xml content
    soap -> http_content  =   " text/xml " ;
    soap_response(soap, SOAP_FILE);
    for (;;)
    {
            
    //  从fd中读取数据
            size_t r  =  fread(soap -> tmpbuf,  1 sizeof (soap -> tmpbuf), fd);
            
    if  ( ! r)
            {
                    
    break ;
            }

            
    //  发送数据
             if  (soap_send_raw(soap, soap -> tmpbuf, r))
            {
                    
    //  can't send, but little we can do about that
                     break ;
            }
    }

    //  关闭fd
    fclose(fd);
    soap_end_send(soap);

    return  SOAP_OK;
修改命名空间前缀

修改gSoapServer工程使用的命名空间前缀。在wsdl中的命名空间为“http://new.webservice.namespace

  • 在typemap.dat文件最后添加一行

      NSNEW="http://new.webservice.namespace"
  • 转换wsdl文件时添加参数

    wsdl2h.exe -t typemap.dat -s -o AddService.h AddService.wsdl
  • 查看函数原型(soapStub.h),可以看到前缀已经被改变
    <!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> SOAP_FMAC5  int  SOAP_FMAC6 __NSNEW__AddOperation( struct  soap * int  A,  int  B,  int   & result);

你可能感兴趣的:(C++,c,webservice,socket,SOAP)