gSoap使用实例 - 发送WSDL文件


http://zgqwork.blog.51cto.com/1721633/495618
2011-02-17 17:43:06

(基于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:

  • 头文件
    // 包含代理类的头文件
    #include " gSoap\soapAddBindingProxy.h "
  • 声明访问代理对象
    AddBinding serviceBinding;
  • 设置访问的WebServiceURL
    serviceBinding.endpoint = ( " http://LocalHost:8082/ " );
  • 调用接口
    int iResult;
    nRetCode
    = serviceBinding.__ns1__AddOperation( 12 , 22 ,iResult);
服务端

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

生成调用代码

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

  • 由.h文件生成具体调用代码:soapcpp2.exe -S AddService.h
  • soapClient.cpp soapClientLib.cpp soapServerLib.cpp这三个文件不需要加入到C++工程中。
实现服务线程
  • 在程序开始时,启动服务线程。
    UINT GSoapServiceThreadFunc(LPVOID p)
    {
    ...
    }
  • 定义编码格式
    // 设置UTF-8编码方式
    soap_set_mode( & soap, SOAP_C_UTFSTRING);
  • 设置服务的端口号
    代码
    // 端口号
    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 );
    }

     

  • 设置 超时
    soap.accept_timeout = 5 ; // 设置GSoap连接超时,单位:秒
  • 创建循环,监听,如果有新连接进来则创建请求处理现场
    代码
    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);
         }
    }

     

实现请求处理线程
相应代码
代码
/// 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 ;
}
实现接口功能函数
在代码中定义相应的接口功能函数
int __ns1__AddOperation( struct soap * , int A, int B, int & result)
{
     result
= A + B;
    
return SOAP_OK;
}

 

函数原型在soapStub.h中定义

 

代码
/* *****************************************************************************\
*                                                                             *
* Service Operations                                                          *
*                                                                             *
\*****************************************************************************
*/

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

 

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

常见问题
支持访问wsdl
  • 首先要设置回调处理函数
    soap.fget = http_get;
    soap.fpost
    = http_post;
  • 两个回调函数的接口定义(stdsoap2.h)
    int ( * fpost)( struct soap * , const char * , const char * , int , const char * , const char * , size_t);
    int ( * fget)( struct soap * );
  • 根据接口定义实现相应的函数
    代码
    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文件名
    代码
    // 请求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文件发送到客户端
    代码
    // 打开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),可以看到前缀已经被改变
    SOAP_FMAC5 int SOAP_FMAC6 __NSNEW__AddOperation( struct soap * , int A, int B, int & result);
带gsoap-2.8源码,基于服务器客户端的实例,带自动生成服务客户端代码的批处理程序,及如何使用。带自己学习参考的教程; 0.解压附件,soapInterface.bat所在路径不得含中文 空格 1.新建头文件soapInterface.bat文件的同名:soapInterface.h 文件内编写接口,具体说明看附件参考的教程 //gsoap ns service name: gservice //gsoap ns service style: rpc int ns__add(int num1, int num2, int* result ); int ns__sub(int num1, int num2, int* result ); int ns__mult( int num1, int num2, int *result); int ns__divid( int num1, int num2, int *result); 2.从附件内gsoap-2.8包中搜索复制stdsoap2.h,stdsoap2.cpp,soapcpp2.exe, 存放于soapInterface.bat同级目录 3.双击soapInterface.bat运行。生成gClientSoap,gServerSoap两个文件夹,分别复制到服务器工程与客户端工程中使用 4.gClientSoap,gServerSoap两个文件夹内用到的文件功能说明,更多参考附件教程 1)soapC.cpp , soapH.h//soap的序列和反序列代码,它已经包含了soapStub.h 2)soapServer.c ppsoapServerLib.cpp //服务器端代码(纯C代码是soapServer.c soapServerLib.c ),soapServerLib.cpp文件则只是简单地包含soapServer.cpp和soapC.cpp 3)soapClient.cpp soapClientLib.cpp//客户端代码(纯C代码是soapClient.csoapClientLib.c ),soapClientLib.cpp文件则只是简单地包含soapClient.cpp和soapC.cpp 4) soapStub.h // soap的存根文件,定义了我们编写的头文件里对应的远程调用模型 5) add.nsmap //XML服务命名空间 6)服务器端要载入的文件有:soapServer.cpp,soapC.cpp,stdsoap2.cpp; 要包含的文件有:gservice.nsmap,soapH.h; 客户端要输入的文件有: soapClient.cpp,soapC.cpp,stdsoap2.cpp; 要包含的文件有:gservice.nsmap,soapH.h
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值