zoukankan      html  css  js  c++  java
  • gSOAP学习笔记

    目录
    一、基本概念
      1.1 关于SOAP
      1.2 关于gSOAP
      1.3 gSOAP编译器(命令行工具)
        1.3.1 wsdl2h
        1.3.2 socapcpp2
    二、gSOAP开发:Web Service服务端
    三、gSOAP开发:Web Service客户端
    四、参考资料
     笔记中的代码
    

    一、基本概念

    1.1 关于SOAP

    SOAP(Simple Object Access Protocol),即简单对象访问协议,是在分布式的环境中交换数据的简单协议,以XML作为数据传送语言。 SOAP有两种工作模式,一种是RPC(Remote Procedure Call),另一种是Message-Oriented。MO可以利用XML来交换结构更复杂的数据。RPC模式的SOAP可以理解为这样一个开发协议:SOAP=RPC+HTTP+XML,具有以下特点:

    • 采用HTTP作为通信协议,采用客户/服务模式;
    • RPC作为统一的远程方法调用途径;
    • 传送的数据使用XML格式。

    看一个简单的请求及回复SOAP数据(真实数据):

    POST /wpsoap/ HTTP/1.1
    Host: 127.0.0.1:10240
    User-Agent: gSOAP/2.7
    Content-Type: text/xml; charset=utf-8; action=""
    Content-Length: 480
    Connection: close
    SOAPAction: ""
     
    <?xml version="1.0" encoding="UTF-8"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://www.example.org/wpsoap/" xmlns:ns2="urn:nszfpt"><SOAP-ENV:Body><ns2:login><req><username>admin</username><password>3.14159</password></req></ns2:login></SOAP-ENV:Body></SOAP-ENV:Envelope>
    
    HTTP/1.1 200 OK
    Server: gSOAP/2.7
    Content-Type: text/xml; charset=utf-8; action=""
    Content-Length: 555
    Connection: close
     
    <?xml version="1.0" encoding="UTF-8"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wpsoap="urn:nszfpt"><SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><wpsoap:tagRspLogin><rsp><retCode>0</retCode><retMessage>login ok!</retMessage></rsp><session>01234567890</session></wpsoap:tagRspLogin></SOAP-ENV:Body></SOAP-ENV:Envelope>
    

    这东西非常的复杂,我仅仅记录一下使用到的部分。

    1.2 关于gSOAP

    引用:http://blog.csdn.net/darkone/archive/2006/12/14/1442525.aspx
    	gSOAP编译工具提供了一个SOAP/XML 关于C/C++ 语言的实现,从而让C/C++语言开发web服务或客户端程序的工作变得轻松了很多。绝大多数的C++web服务工具包提供一组API函数类库来处理特定的SOAP数据结构,这样就使得用户必须改变程序结构来适应相关的类库。与之相反,gSOAP利用编译器技术提供了一组透明化的SOAP API,并将与开发无关的SOAP实现细节相关的内容对用户隐藏起来。gSOAP的编译器能够自动的将用户定义的本地化的C或C++数据类型转变为符合XML语法的数据结构,反之亦然。这样,只用一组简单的API就将用户从SOAP细节实现工作中解脱了出来,可以专注与应用程序逻辑的实现工作了。gSOAP编译器可以集成C/C++和Fortran代码(通过一个Fortran到C的接口),嵌入式系统,其他SOAP程序提供的实时软件的资源和信息;可以跨越多个操作系统,语言环境以及在防火墙后的不同组织。
    	gSOAP使编写web服务的工作最小化了。gSOAP编译器生成SOAP的代码来序列化或反序列化C/C++的数据结构。gSOAP包含一个WSDL生成器,用它来为你的web服务生成web服务的解释。gSOAP的解释器及导入器可以使用户不需要分析web服务的细节就可以实现一个客户端或服务端程序。
    

    照我理解,gSOAP可以为我们生成soap服务器端+客户端代码的框架,我们只需实现具体的接口函数即可。而生成代码的工具就是上面文中提到的“gSOAP编译器”。

    1.3 gSOAP编译器(命令行工具)

    1.3.1 wsdl2h

    此工具用来从WSDL文件生成c/c++头文件。

    wsdl2h -o 头文件名 WSDL文件名或URL
    常用的其它参数:
    -o 文件名,指定输出头文件
    -n 名空间前缀 代替默认的ns
    -c 产生纯C代码,否则是C++代码
    -s 不要使用STL代码
    -t 文件名,指定type map文件,默认为typemap.dat
    -e 禁止为enum成员加上名空间前缀
    

    1.3.2 socapcpp2

    此工具用来从头文件,生成SOAP服务器及客户端代码,还包括WSDL、测试用XML数据。

    soapcpp2 头文件
    常用选项
    -C 仅生成客户端代码
    -S 仅生成服务器端代码
    -L 不要产生soapClientLib.c和soapServerLib.c文件
    -c 产生纯C代码,否则是C++代码(与头文件有关)
    -I 指定import路径(见上文)
    -x 不要产生XML示例文件
    -i 生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)。
    

    二、gSOAP开发:Web Service服务端

    开发服务器程序,需使用gSOAP生成服务器端代码框架。我们有两种做法:

    1. 编写WSDL,使用wsdl2h生成头文件,再soapcpp2生成框架代码;
    2. 编写头文件,使用soapcpp2生成框架代码;

    这两种方式,结果是一样的,最终都有产生头文件,并生成代码。不同在于,在项目的开发中需要维护的文件不同,前者是需要维护WSDL文件,后者维护头文件。

    我个人觉得第二种方式更好用,不仅仅是少了个步骤,而是WSDL的语法太难写了,有点XSD的味道。而头文件的编写,更接近于程序员的思考方式,比如定义消息结构,定义接口名称等。

    gSOAP是非常智能的,它利用C/C++的注释来获取信息,所以在手工编写的头文件中,注释是用用处的,常以// gsoap 名字空间 …开头。做为学习,我准备为php blog程序wordpress写一个web service接口,名字叫wpsoap。

    我开始写头文件(wpSoap.h)了,出于学习目的,我仅实现了两个接口:一是用户登陆;一是日志发布。

    /**
     * @file wpsoap.h
     * @brief 为wordpress2.7提供web service接口
     *
     *  "//gsoap"开头行,请勿删除.
     * 
     *  1. 通过此文件生成WSDL 及 服务端代码
     * 
     *    >mkdir -p srvSrcFromH
     *    >cd srvSrcFromH
     *    >soapcpp2 -L -S "wpsoap.h" -I /path/to/gsoap-2.8/gsoap/import/
     * 
     *  2. 通过WSDL生成客户端代码
     * 
     *    >mkdir -p clientSrcFromWSDL
     *    >cd clientSrcFromWSDL
     *    >wsdl2h.exe  -o wpsoap.h ../srvSrcFromH/wpsoap.wsdl -I /path/to/gsoap-2.8/gsoap/import/
     *    >soapcpp2 -L -C wpsoap.h -I /path/to/gsoap-2.8/gsoap/import/
     *
     * @author pansunyou@gmail.com
     * @version 1.0
     * @date 2010-12-27
    */
     
    //gsoap wpsoap service name: wpsoap
    //gsoap wpsoap service namespace: http://www.example.org/wpsoap/
    //gsoap wpsoap service location: http://192.168.0.187:10240/wpsoap/
    //gsoap wpsoap service encoding: encoded
    //gsoap wpsoap schema namespace: urn:nszfpt
     
    #import "stlvector.h"
     
    //通用回复
    class wpsoap__tagCommResponse
    {
           int			retCode		;      //回复码
           std::string retMessage	;      //回复消息
    };
     
    //[请求]用户登陆
    class wpsoap__tagReqLogin
    {
        std::string username        ;      //用户名
        std::string password        ;      //密码名文
    };
     
    //[答复]用户登陆
    class wpsoap__tagRspLogin
    {
        wpsoap__tagCommResponse rsp	 ;      //通用回复
           std::string session       ;      //会话标识
    };
     
    //[接口]登陆接口
    int wpsoap__login(wpsoap__tagReqLogin req, wpsoap__tagRspLogin& rsp);
     
     
    //[请求]发布日志
    class wpsoap__tagReqPost
    {
        std::string title			  ;      //标题
        std::string body              ;      //正文
    };
     
    //[答复]发布日志
    class wpsoap__tagRspPost
    {
        wpsoap__tagCommResponse rsp    ;      //通用回复
    };
     
    //[接口]发布日志接口
    int wpsoap__post(wpsoap__tagReqPost req, wpsoap__tagRspPost& rsp);
    

    在接口中,我使用到了自定义的消息结构wp_soap_tag*,这里的wpsoap__前缀是必须的,这样soapcpp2才能为我们生成正确的代码。

    之后,我使用soapcpp2生成服务端代码框架:

    @echo off
    @set path=%cd%....contribgsoap-2.8gsoapinwin32;%path%
     
    mkdir srvSrcFromH 2>nul
    cd srvSrcFromH
    soapcpp2.exe -L -S ..
    eswpSoap.h -I ......contribgsoap-2.8gsoapimport
    pause
    

    要编译出服务程序,有这些代码还不够,还需要自己写两个文件,一个用来写main函数,一个用来写wpsoap的接口函数(当然可以放在一个文件里)。最终我的服务器程序有以下文件:(另外,还需要gsoap目录下的stdsoap2.cpp,因为我把它编译为静态库了,所以这里没列出来。)

    D:wpSoapServer
    |   makeSrc.bat
    |   wpsoapimpl.cpp                //这里实现了soapStub.h给出的接口
    |   wpsoapsrv.cpp                  //这里是main函数开始的地方
    +---res
    |       wpSoap.h
    ---srvSrcFromH
            soapC.cpp
            soapH.h
            soapServer.cpp
            soapStub.h
            soapwpsoapObject.h
            wpsoap.login.req.xml
            wpsoap.login.res.xml
            wpsoap.nsmap
            wpsoap.post.req.xml
            wpsoap.post.res.xml
            wpsoap.wsdl
            wpsoap.xsd
    

    每次我修改了res/wpSoap.h后,我就运行一下makeSrc.bat,自动重新生成srvSrcFromH目录里的所有东西,并且这个目录里的所有代码是不需要手工维护的(除非有特殊需要)。

    在服务器代码中,我仅实现了以下两个函数(wpsoapimpl.cpp):

    int wpsoap__login(struct soap*, wpsoap__tagReqLogin req, wpsoap__tagRspLogin &rsp);
    int wpsoap__post(struct soap*, wpsoap__tagReqPost req, wpsoap__tagRspPost &rsp);
    

    wpsoapsrv.cpp里的代码仅仅是调用gSOAP产生的代码来建立socket服务器,基本不需维护。gSOAP是线程安全的,可以将请求分配到线程池内实现高效服务,但我仅为了走通gSOAP的使用流程,没有这样使用。

    具体做法可以参考:http://www.cs.fsu.edu/~engelen/soapdoc2.html

    三、gSOAP开发:Web Service客户端

    客户端代码本来也是可以通过为服务端编写的头文件生成的,但是为了真实一点,假设我无法获取服务器开发时使用的头文件,仅仅有个公开的WSDL文件,就是上面产生的srvSrcFromH /wpsoap.wsdl。

    我用这个脚本来生成客户端框架代码:

    @echo off
    @set path=%cd%....contribgsoap-2.8gsoapinwin32;%path%
     
    mkdir clientSrcFromWSDL 2>nul
    cd clientSrcFromWSDL
    wsdl2h.exe -o wpsoap.h ....wpSoapServersrvSrcFromHwpsoap.wsdl
    soapcpp2.exe -L -C wpsoap.h -I ......contribgsoap-2.8gsoapimport
    pause
    

    加上我测试用的代码wpsoapclient.cpp,以及gosap目录里的stdsoap2.cpp,我有了如下文件:

    D:wpSoapClient
    |   makeSrc.bat
    |   wpsoapclient.cpp
    ---clientSrcFromWSDL
            soapC.cpp
            soapClient.cpp
            soapH.h
            soapStub.h
            soapwpsoapProxy.h
            wpsoap.h
            wpsoap.login.req.xml
            wpsoap.login.res.xml
            wpsoap.nsmap
            wpsoap.post.req.xml
            wpsoap.post.res.xml
    

    客户端代码非常少(仅仅是实现,容错之类的都未考虑):

    /**
     * @file wpsoapclient.cpp
     * @brief 访问wpsoap服务
     *
     * 调用wpsoap的客户端示例代码
     *
     * @author pansunyou@gmail.com
     * @version 1.0
     * @date 2010-12-27
    */
     
    #define _CRT_SECURE_NO_WARNINGS
    #include <cstdio>
    #include <cstdlib>
    #include <string>
    #include "clientSrcFromWSDL/soapStub.h"
    #include "clientSrcFromWSDL/soapwpsoapProxy.h"
    #include "clientSrcFromWSDL/wpsoap.nsmap"
     
    using namespace std;
     
    int main(int argc, char*argv[])
    {
      wpsoap wpsoapClient;
      if (argc==2)
        wpsoapClient.endpoint = argv[1];
     
      //1. 登陆
      string username = "admin";
      string password = "3.14159";
      int r = 0;
     
      ns2__tagReqLogin req;
      req.username = username;
      req.password = password;
      _ns2__login ns2__login;
      ns2__login.req = &req;
      _ns2__tagRspLogin rsp;
      r = wpsoapClient.__ns1__login(&ns2__login, &rsp);
      if (r!=0)
      {
        fprintf(stderr, "调用soap接口失败!
    ");
        return -1;
      }
     
      if (0!=rsp.rsp->retCode)
      {
        printf("登陆失败 retCode=%d, retMessage=%s
    ",
    		rsp.rsp->retCode, 
    		rsp.rsp->retMessage.c_str());
        return -1;
      }
      printf("登陆成功! [session=%s]
    ",
    	rsp.session.c_str());
     
            
      ns2__tagReqPost reqPost;
      reqPost.body = "post article by wpsoap!";
      reqPost.title = "hello, wpsoap!";
     
      _ns2__post ns2__post;
      ns2__post.req = &reqPost;
      _ns2__tagRspPost ns2__tagRspPost;
      r = wpsoapClient.__ns1__post(&ns2__post, 
    	&ns2__tagRspPost);
      if (r!=0)
      {
        fprintf(stderr, "调用soap接口失败!
    ");
        return -1;
      }
     
      if (0!=rsp.rsp->retCode)
      {
        printf("发布日志失败 retCode=%d, 
    		retMessage=%s
    ",
    		rsp.rsp->retCode, 
    		rsp.rsp->retMessage.c_str());
        return -1;
      }
      printf("日志发布成功! [retMessage=%s]
    ", 
      rsp.rsp->retMessage.c_str());
      
      return 0;
    }
    

    四、参考资料

    http://gsoap2.sourceforge.net/ http://www.cppprog.com/2009/0723/138.html

    http://hi.baidu.com/winnyang/blog/item/d5fd4f3df38f35cd9e3d625b.html http://www.cs.fsu.edu/~engelen/soap.html http://tangentsoft.net/mysql++/

    有志者事竟成
  • 相关阅读:
    17.1.2.1 Advantages and Disadvantages of Statement-Based and Row-Based Replication
    17.1.2 Replication Formats
    Setting the Master Configuration on the Slave
    17.1.1.9 Introducing Additional Slaves to an Existing Replication Environment
    17.1.1.8 Setting Up Replication with Existing Data
    17.1.1.7 Setting Up Replication with New Master and Slaves
    17.1.1.6 Creating a Data Snapshot Using Raw Data Files
    列出display的值,并说明它们的作用
    CSS设置DIV居中
    CSS选择符有哪些?哪些属性可以继承?优先级算法如何计算?
  • 原文地址:https://www.cnblogs.com/dancheblog/p/3723501.html
Copyright © 2011-2022 走看看