由onvif的wsdl文件生成客户端和服务器端代码

时间:2022-12-02 08:44:40

gSoap开发包的下载地址http://sourceforge.net/projects/gsoap2

下载最新gSoap程序包
解压后在\gsoap\bin\win32(windowsXP下,其它操作系统就自己选择)下找到 编译器soapcpp2.exe 和wsdl解析工具 wsdl2h.exe

开发客户端和服务器端程序
    (1)客户端服务端通信必不可少的一个东西:接口定义。
          gSoap使用中,需要此接口文件(也就是以后常提到的头文件)此文件可以两种方式得到:
          1: 由现有的wsdl文件转换得到(本文使用这种方式,使用onvif官网提供的wsdl文件)
          2: 自己编写

    (2)两个工具的用途
          wsdl2h.exe--------名字就能看出来,完成 wsdl文件(.wsdl)到(2)头文件(.h)的转换,即由写好的wsdl格式的接口定义文件转换为C/C++格式的头文件         

          soapcpp2.exe------根据接口头文件生成应用程序客户端和服务端的框架文件(soapClient.cpp、soapServer.cpp等).


结合例子说明过程
      由wsdl文件生成接口头文件
      wsdl文件URL地址:http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl
      操作流程
      a) 程序->运行 输入cmd 启动命令行;
      b) 打开wsdl2h.exe所在文件路径(gsoap-2.8\gsoap\bin\win32);
      c) 输入:wsdl2h.exe -o devicemgmt.h http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl 
         其中
             "wsdl2h.exe",因为第二步中打了wsdl2h文件所在路径,所以此处可以直接用了,若没打开要输入所在完整路径
             "devicemgmt.h"为生成的头文件名,此文件的保存位置在wsdl2h.exe同一文件目录下

  执行时,会产生如下错误:Critical error: #import: Cannot open file "ns1.h" for reading.

       错误原因是devicemgmt.h里有如下代码  #import "ns1.h" // ns1 = <http://www.w3.org/2005/08/addressing>

解决办法如果通过下面方式避免这个问题:
        根据wsdl生成头文件时,加1个xsd文件
       wsdl2h.exe -o devicemgmt.h http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl  http://www.w3.org/2006/03/addressing/ws-addr.xsd

             wsdl2h常用选项:

  •             -o 文件名,指定输出头文件
  •             -c 产生纯C代码,否则是C++代码
  •             -s 不要使用STL代码
  •             -t 文件名,指定type map文件,默认为typemap.dat

            typemap文件用于指定SOAP/XML中的类型与C/C++之间的转换规则,比如在wsmap.dat里写

<span style="font-size:12px;">          xsd__string = | std::wstring | wchar_t*</span>

             那么SOAP/XML中的string将转换成std::wstring或wchar_t*,这样能更好地支持中文

             例:

              wsdl2h -o ayandy.h   -n ay -t wsmap.dat http://www.ayandy.com/Service.asmx?WSDL

             从http://www.ayandy.com/Service.asmx?WSDL 生成ayandy.h文件,名空间为ay,使用wsmap.dat指定的转换规则。

              wsdl2h生成的头文件里的变量、类型等名称的前面都会加上名空间前缀,以两个下划线分隔。如上面的命令生成的头文件,有这样的定 义:

  1.       class ay1__ArrayOfString;
  2.       enum ay1__theDayFlagEnum
  3.       {
  4.         ay1__theDayFlagEnum__Today,
  5.         ay1__theDayFlagEnum__Tomorrow,
  6.         ay1__theDayFlagEnum__theDayafterTomorrow,
  7.      };
由onvif的wsdl文件生成客户端和服务器端代码

     前面的ayandy1__的是名空间前缀,用以防止名称冲突。 wsdl2h的-n选项可以改变这个名空间前缀(默认为ns)。对于枚举ay1__theDayFlagEnum内 的成员,        如果嫌它太长的话,可以用-e命令选项禁止加入名空间前缀。

    d) 回车 运行吧,看提示信息,没有提示故障的话,会生成devicemgmt.h文件(wsdl2h.exe所在的目录)
    e) 得到devicemgmt.h后,打开可以看到接口定义;
    f) 在命令行中 输入:soapcpp2.exe devicemgmt.h
         其中
             "soapcpp2.exe",此处把soapcpp2.exe和wsdl2h.exe放在同一目录下了,且前面已打开此路径;
             "devicemgmt.h"即由wsdl生成的头文件,此文件保存位置与soapcpp2.exe相同
             可以增加控制选项如"soapcpp2.exe -C cal.h"则只生成客户端所需文件, "soapcpp2.exe -S calc.h"则只生成服务端所需文件

             执行时,会产生如下错误:Critical error: #import: Cannot open file "stl.h" for reading.

                                                 Hint :use option -I<path><for example -Igsoap/import;gsoap/custom:.>

产生原因:你的头文件使用了STL(wsdl2h 没用-s选项),这时要使用-I选项指定gSOAP的 import文件路径。你的头文件使用了STL(wsdl2h 没用-s选项)

解决办法:添加 -I选项,指定import目录的stl.h文件的路径 soapcpp2.exe -I ..\..\import devicemgmt.h 

 

     soapcpp2常用选项

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

  h) 编译成功,生成的框架文件保存位置与devicemgmt.h 在同一目录下

     其中

  •     soapStub.h    // soap的存根文件,定义了devicemgmt.h里对应的远程调用模型
  •    soapC.c soapH.h // soap的序列和反序列代码,它已经包含了soapStub.h,服务器端与客户端都要包含它
  •    soapClient.c soapClientLib.c // 客户端代码,soapClientLib.c文件则只是简单地包含soapClient.c和soapC.c
  •    soapServer.c soapServerLib.c // 服务器端代码,soapServerLib.c文件则只是简单地包含soapServer.c和soapC.c
  •    DeviceBinding.nsmap // 名空间定义,服务器端与客户端都要包含它

综上所述

  • 如果编写服务器端,项目里应该加入soapServerLib.c,代码里包含头文件soapH.h
  • 如果编写客户端,项目里应该加入soapClientLib.c,代码里包含头文件SoapH.h)
  • 当然,还要加入gsoap库里的stdsoap2.cpp文件(如果是写C代码,则加入stdsoap2.c)