ONVIF协议网络摄像机(IPC)客户端程序开发(6):使用gSOAP生成ONVIF框架代码

1. 专栏导读

本专栏第一篇文章「专栏开篇」列出了专栏的完整目录,按目录顺序阅读,有助于你的理解,专栏前面文章讲过的知识点(或代码段),后面文章不会赘述。为了节省篇幅,突出重点,在文章中展示的示例代码仅仅是关键代码,你可以在「专栏开篇」中获取完整代码。

如有错误,欢迎你的留言纠正!让我们共同成长!你的「点赞」「打赏」是对我最大的支持和鼓励!

2. 前言

前一篇文章介绍了什么是ONVIF,也梳理了ONVIF开发流程,本文接着介绍些如何使用gSOAP工具生成ONVIF协议框架代码。

本文生成的ONVIF协议框架代码,后续文章都会用到,我这里会考虑生成「大而全」的代码以支撑后续的文章。主要体现在:

  • 一次性把所有可能会用到的WSDL文档都纳入编译,以便得到一份尽可能齐全的ONVIF接口代码。我这样做是为了省事,但我希望你在心底里能明白一件事情:ONVIF有好多个模块,每个模块分别对应着不同的WSDL文档,如果你只是想实现其中某个模块的功能,其实只要拿那个模块对应的WSDL文档来编译即可(可以忽略其他WSDL)。比如你只是想实现「设备发现」功能,只要拿remotediscovery.wsdl来编译即可。

  • 为了让代码同时兼容Windows和Linux两个平台(未考虑其他平台),在我后续专栏中的示例代码都会做一些兼容性的处理。如果你是用Windows来开发,那得用Microsoft Visual Studio SP1(或更高版本),后续会涉及到SOAP协议数据「中文字符乱码」的问题,Microsoft Visual Studio SP1以下的版本不好处理。

  • 把我所遇到的问题尽可能的提前进行说明,至于没其他问题,只能大家自己搞定了,也欢迎大家来一起交流(留言/邮箱)。

3. gSOAP工具下载

gSOAP官方网址:http://www.cs.fsu.edu/~engelen/soap.html

gSOAP开源版下载网址(最新版本):http://sourceforge.net/projects/gsoap2

gSOAP开源版下载网址(历史版本):https://sourceforge.net/projects/gsoap2/files/gSOAP/

gSOAP有分商业版「commercial edition」和开源版「open source edition」,我撰写本专栏用的是gSOAP开源版「gsoap_2.8.45」。

4. wsdl2h和soapcpp2简介

要用gsoap生成onvif源码,必须用到wsdl2h和soapcpp2两个工具(执行文件)。在gsoap\bin目录下,win32和macosx平台已经有现成的了(官方帮我们编译好了的),linux下的要自己编译咯,可参考INSTALL.txt文件进行编译安装(不同gSOAP版本的编译安装方法会略有不同,以你gSOAP版本中的INSTALL.txt为准)。

通过实验证实,wsdl2h和soapcpp2两个工具,不管是Windows版的,还是Linux版的,它们从WSDL转成的框架代码,是一样样的,没有区别。

5. wsdl2h不支持HTTPS

既然有现成的Windows版wsdl2h.exe,那就直接拿来用咯。结果让人沮丧,在从ONVIF的WSDL转为头文件时出错,错误信息如下:

wsdl2h.exe -P -x -o onvif.h -c -s -t typemap.dat  https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl https://www.onvif.org/ver10/media/wsdl/media.wsdl
Saving onvif.h


**  The gSOAP WSDL/WADL/XSD processor for C and C++, wsdl2h release 2.8.45
**  Copyright (C) 2000-2017 Robert van Engelen, Genivia Inc.
**  All Rights Reserved. This product is provided "as is", without any warranty.
**  The wsdl2h tool and its generated software are released under the GPL.
**  ----------------------------------------------------------------------------
**  A commercial use license is available from Genivia Inc., contact@genivia.com
**  ----------------------------------------------------------------------------

Reading type definitions from type map "typemap.dat"

Cannot connect to https site: SSL/TLS support not enabled, please rebuild wsdl2h with SSL/TLS enabled using 'make secure' or download the WSDL/WADL and XSD files and rerun wsdl2h on these files directly by specifying the file names on the command line.

从提示信息也能看出大概意思,就是wsdl2h不支持SSL/TLS,无法下载HTTPS文件。我2016年9月份也有用gSOAP生成ONVIF代码,为啥没碰到这个问题,而现在(2017年4月25日)却碰到了?

早期,ONVIF的WSDL文档URL地址是HTTP开头的(不会出现这个问题),2017年3月底ONVIF官网进行了一次改版,改版之后WSDL的URL地址变成HTTPS的了,即使你访问早期的HTTP地址,如:

http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl

最终也会被跳转到HTTPS地址:

https://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl

gSOAP官方提供的、已编译好的wsdl2h默认是禁用SSL/TLS的,所以不支持HTTPS下载WSDL文件。至少我的版本gsoap_2.8.45是如此,未来的版本会如何只能靠大家自己尝试。根据出错的提示信息,有两种解决办法:

  1. 重新编译gSOAP源码,生成带SSL/TLS的wsdl2h工具。
  2. 自己手动下载WSDL文档后,再用本地WSDL文档执行wsdl2h命令。

网上很多教程有提到使用第2种方法,这对其他的WSDL文档可能合适,但对ONVIF的WSDL不合适,ONVIF的WSDL文档会依赖其他WSDL和xsd文档,依赖关系隐藏在每个WSDL文档中,一般人很难厘清这里面复杂的依赖关系,容易出错,也整不清楚xsd文件该从哪里下载。

所以这里推荐用第1种方法,如何编译gSOAP源码,以便得到开启SSL/TLS的wsdl2h,不同版本的gSOAP方法不同,具体要参考对应gSOAP版本中的INSTALL.txt文件说明。

6. 编译gSOAP源码让wsdl2h支持HTTPS

下面介绍下如何在linux平台下重新编译gSOAP源码,以便得到开启SSL/TLS的wsdl2h,从而让wsdl2h支持HTTPS。

6.1 准备环境

在编译安装之前,必须先安装以下几个要用到的软件(在INSTALL.txt文件中有说明):

  1. 安装Bison

    我采用源码编译安装的方式:

    官网:http://www.gnu.org/software/bison/
    版本:bison-2.7.91.tar.gz
    安装:详见bison-2.7.91/INSTALL说明

  2. 安装Flex

    我采用源码编译安装的方式:

    官网:http://flex.sourceforge.net/
    版本:flex-2.6.0.tar.gz
    安装:详见flex-2.6.0/INSTALL说明

  3. 安装OpenSSL

    我采用源码编译安装的方式:

    官网:https://www.openssl.org/
    版本:openssl-1.0.2h
    安装:详见openssl-1.0.2h/INSTALL说明
    备注:我采用默认安装路径/usr/local/ssl/,这个路径等下编译gSOAP源码时会用到

6.2 编译gSOAP源码

如何编译,参考gsoap-2.8/INSTALL.txt说明:

$ cat INSTALL.txt

INSTALLATION

See README.txt for an overview of the gSOAP software.

Visit www.genivia.com/downloads.html for download and installation instructions.

按提示,访问www.genivia.com/downloads.html查看详细的安装说明,详见「Installing gSOAP on Unix/Linux」章节,除此之外,你也可以通过./configure -h查看更多的帮助信息。

编译gSOAP源码的命令如下:

$ cd gsoap-2.8
$ ./configure --with-openssl=/usr/local/ssl
$ make
$ make install

期间如果提示找不到OpenSSL库文件,那检查下–with-openssl有没有指向正确的路径。

查看wsdl2h和soapcpp2被安装到哪里了:

$ which wsdl2h soapcpp2
/usr/local/bin/wsdl2h
/usr/local/bin/soapcpp2

看是否能运行:

$ wsdl2h -h
wsdl2h: error while loading shared libraries: libssl.so.1.0.0: cannot open shared object file: No such file or directory

提示找不到OpenSSL动态库文件,解决方法:

  1. 将.so文件路径「/usr/local/ssl/lib」追加到/etc/ld.so.conf文件末尾。

    $ echo /usr/local/ssl/lib >> /etc/ld.so.conf
  2. 使得修改立刻生效:

    $ ldconfig

至此wsdl2h就能正常运行了。

7. 使用gSOAP生成ONVIF框架代码

gSOAP官网上有一篇文章「How do I use gSOAP with the ONVIF specifications」,专门介绍如何使用gSOAP生成ONVIF框架代码,链接如下:

地址:https://www.genivia.com/resources.html

找到「How do I use gSOAP with the ONVIF specifications」章节。

操作步骤如下:

(1). 参考gSOAP官网说明修改gsoap\typemap.dat

参考「How do I use gSOAP with the ONVIF specifications」(https://www.genivia.com/resources.html)说明,看是否需要修改typemap.dat。我用的gSOAP工具版本是gsoap_2.8.45,typemap.dat文件刚好符合要求,不用改。

(2). 使用wsdl2h工具,根据WSDL产生头文件

创建一个目录samples/onvif,用于存放生成的ONVIF框架源码。

$ cd gsoap-2.8/gsoap/
$ mkdir -p samples/onvif
$ wsdl2h -P -x -c -s -t ./typemap.dat -o samples/onvif/onvif.h https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl https://www.onvif.org/ver10/media/wsdl/media.wsdl

各个选项的含义,可通过wsdl2h.exe -help查看帮助。其中-c为产生纯c代码,不然为c++代码;-s为不使用STL库,-t为typemap.dat的标识。

命令成功执行后会得到onvif.h头文件,命令执行过程如下:

$ wsdl2h -P -x -c -s -t ./typemap.dat -o samples/onvif/onvif.h https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl https://www.onvif.org/ver10/media/wsdl/media.wsdl
Saving samples/onvif/onvif.h


**  The gSOAP WSDL/WADL/XSD processor for C and C++, wsdl2h release 2.8.45
**  Copyright (C) 2000-2017 Robert van Engelen, Genivia Inc.
**  All Rights Reserved. This product is provided "as is", without any warranty.
**  The wsdl2h tool and its generated software are released under the GPL.
**  ----------------------------------------------------------------------------
**  A commercial use license is available from Genivia Inc., contact@genivia.com
**  ----------------------------------------------------------------------------

Reading type definitions from type map "./typemap.dat"
Connecting to 'https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl' to retrieve WSDL/WADL or XSD... connected, receiving...
Done reading 'https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl'
Connecting to 'https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl' to retrieve WSDL/WADL or XSD... connected, receiving...
  Connecting to 'https://www.onvif.org/ver10/device/wsdl/../../../ver10/schema/onvif.xsd' to retrieve schema '../../../ver10/schema/onvif.xsd'... connected, receiving...
    Connecting to 'http://docs.oasis-open.org/wsn/b-2.xsd' to retrieve schema... connected, receiving...
      Connecting to 'http://docs.oasis-open.org/wsrf/bf-2.xsd' to retrieve schema... connected, receiving...
      Done reading 'http://docs.oasis-open.org/wsrf/bf-2.xsd'
      Connecting to 'http://docs.oasis-open.org/wsn/t-1.xsd' to retrieve schema... connected, receiving...
      Done reading 'http://docs.oasis-open.org/wsn/t-1.xsd'
    Done reading 'http://docs.oasis-open.org/wsn/b-2.xsd'
    Connecting to 'https://www.onvif.org/ver10/device/wsdl/../../../ver10/schema/common.xsd' to retrieve schema... connected, receiving...
    Done reading 'https://www.onvif.org/ver10/device/wsdl/../../../ver10/schema/common.xsd'
  Done reading '../../../ver10/schema/onvif.xsd'
Done reading 'https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl'
Connecting to 'https://www.onvif.org/ver10/media/wsdl/media.wsdl' to retrieve WSDL/WADL or XSD... connected, receiving...
Done reading 'https://www.onvif.org/ver10/media/wsdl/media.wsdl'

Warning: 2 service bindings found, but collected as one service (use option -Nname to produce a separate service for each binding)

To finalize code generation, execute:
> soapcpp2 samples/onvif/onvif.h

(3). 因「鉴权(认证)」需要,修改onvif.h头文件

有些ONVIF接口调用时需要携带认证信息,要使用soap_wsse_add_UsernameTokenDigest函数进行授权,所以要在onvif.h头文件开头加入

#import "wsse.h"

如果onvif.h不加入#import "wsse.h",使用soap_wsse_add_UsernameTokenDigest函数会导致编译出错(错误信息如下):

wsse2api.c(183): error C2039: “wsse__Security”: 不是“SOAP_ENV__Header”的成员

(4). 使用soapcpp2工具,根据头文件产生框架代码

$ soapcpp2 -2 -C -L -c -x -I import:custom -d samples/onvif/ samples/onvif/onvif.h

各个选项的含义,通过soapcpp2.exe -help查看帮助。

根据不同的gSOAP版本,这个过程你可能会遇到这样的错误:

wsa5.h(288): **ERROR**: service operation name clash: struct/class 'SOAP_ENV__Fault' already declared at wsa.h:273

之所有会出现这个错误,是因为onvif.h头文件中同时:

#import "wsdd10.h" // wsdd10.h中又#import "wsa.h"
#import "wsa5.h"   // wsa.h和wsa5.h两个文件重复定义了int SOAP_ENV__Fault

解决方法:修改import\wsa5.h文件,将int SOAP_ENV__Fault修改为int SOAP_ENV__Fault_alex,再次使用soapcpp2工具编译就成功了,命令执行过程如下:

$ soapcpp2 -2 -C -L -c -x -I import:custom -d samples/onvif/ samples/onvif/onvif.h  

**  The gSOAP code generator for C and C++, soapcpp2 release 2.8.45
**  Copyright (C) 2000-2017, Robert van Engelen, Genivia Inc.
**  All Rights Reserved. This product is provided "as is", without any warranty.
**  The soapcpp2 tool and its generated software are released under the GPL.
**  ----------------------------------------------------------------------------
**  A commercial use license is available from Genivia Inc., contact@genivia.com
**  ----------------------------------------------------------------------------


soap12.h(54): *WARNING*: option -1 or -2 overrides SOAP-ENV namespace


soap12.h(55): *WARNING*: option -1 or -2 overrides SOAP-ENC namespace

Using project directory path: samples/onvif/
Saving samples/onvif/soapStub.h annotated copy of the source interface file
Saving samples/onvif/soapH.h serialization functions to #include in projects
Using wsdd service name: wsdd
Using wsdd service style: document
Using wsdd service encoding: literal
Using wsdd schema import namespace: http://schemas.xmlsoap.org/ws/2005/04/discovery
Saving samples/onvif/wsdd.nsmap namespace mapping table
Using tdn service name: RemoteDiscoveryBinding
Using tdn service style: document
Using tdn service encoding: literal
Using tdn schema namespace: http://www.onvif.org/ver10/network/wsdl
Saving samples/onvif/RemoteDiscoveryBinding.nsmap namespace mapping table
Using tds service name: DeviceBinding
Using tds service style: document
Using tds service encoding: literal
Using tds schema namespace: http://www.onvif.org/ver10/device/wsdl
Saving samples/onvif/DeviceBinding.nsmap namespace mapping table
Using trt service name: MediaBinding
Using trt service style: document
Using trt service encoding: literal
Using trt schema namespace: http://www.onvif.org/ver10/media/wsdl
Saving samples/onvif/MediaBinding.nsmap namespace mapping table
Saving samples/onvif/soapClient.c client call stub functions
Saving samples/onvif/soapC.c serialization functions

Compilation successful (2 warnings)

(5). 拷贝其他还有会用的源码

$ cp stdsoap2.c stdsoap2.h plugin/wsaapi.c plugin/wsaapi.h custom/duration.c custom/duration.h  samples/onvif/

soapC.c会调用到soap_in_xsd__duration函数,需要duration.c和duration.h文件。

后续示例代码会调用到soap_wsa_rand_uuid函数(用于生成UUID),需要wsaapi.c和wsaapi.h文件。

(6). 关联自己的命名空间,修改stdsoap2.c文件

在samples\onvif\stdsoap2.h中有命名空间「namespaces变量」的定义声明,如下所示:

extern SOAP_NMAC struct Namespace namespaces[];

但「namespaces变量」的定义实现,是在samples\onvif\wsdd.nsmap文件中,为了后续应用程序要顺利编译,修改samples\onvif\stdsoap2.c文件,在开头加入:

#include "wsdd.nsmap"

当然,你可以在其他源码中(更上层的应用程序源码)include,我这里是选择在stdsoap2.c中include

(7). 大功告成

至此,我开发IPC客户端程序要用到的ONVIF框架代码已经生成。我专栏里的上层实例代码就是基于这份ONVIF框架代码而开发的。

$ ls -l onvif/
总用量 9796
-rwxrwxrwx 1 root root    2254 427 17:02 DeviceBinding.nsmap
-rwxrwxrwx 1 root root    6725 429 14:30 duration.c
-rwxrwxrwx 1 root root    4051 429 14:30 duration.h
-rwxrwxrwx 1 root root    2254 427 17:02 MediaBinding.nsmap
-rwxrwxrwx 1 root root 3031182 427 16:57 onvif.h
-rwxrwxrwx 1 root root    2254 427 17:02 RemoteDiscoveryBinding.nsmap
-rwxrwxrwx 1 root root 9277873 427 17:02 soapC.c
-rwxrwxrwx 1 root root  406017 427 17:02 soapClient.c
-rwxrwxrwx 1 root root 5158122 427 17:02 soapH.h
-rwxrwxrwx 1 root root 1344868 427 17:02 soapStub.h
-rwxrwxrwx 1 root root  593718 429 14:30 stdsoap2.c
-rwxrwxrwx 1 root root  151026 429 14:30 stdsoap2.h
-rwxrwxrwx 1 root root   64006 429 14:29 wsaapi.c
-rwxrwxrwx 1 root root    7153 429 14:29 wsaapi.h
-rwxrwxrwx 1 root root    2254 427 17:02 wsdd.nsmap

其中onvif.h文件其实已经没用了,可以删掉,不需要参与后续IPC客户端程序的编译。这里有好多个命名空间的.nsmap文件,文件内容都一模一样,拿wsdd.nsmap一个来用即可,其他也没卵用。

8. 我的封装

开发调用ONVIF接口的应用程序,会比较枯燥,很多复杂、粘贴,而且会很多重复代码,为了减少冗余,也为了后续专栏更好展示关键代码,我对常用的、会频繁调用的ONVIF接口做了二次封装,详细的代码,请参考「《ONVIF协议网络摄像机(IPC)客户端程序开发》专栏的示例代码」中的comm文件夹,代码下载地址详见前面的「专栏导读」。

  • 56
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 63
    评论
ONVIF协议是一种开放的网络视频接口标准,旨在实现网络摄像机网络视频录像机和其他相关设备的互通互联。在开发ONVIF协议网络摄像机客户端程序时,我们需要遵循以下步骤: 首先,为了开发ONVIF协议网络摄像机客户端程序,我们需要对ONVIF协议进行深入了解。ONVIF协议定义了网络摄像机和客户端之间的通信规则和接口,包括设备发现、视频流传输、设备控制等。我们需要熟悉协议的各个方面,包括消息结构、命令和响应等。 其次,我们需要选择合适的开发平台和工具。ONVIF协议可以在不同平台上运行,如Windows、Linux等。我们可以选择适合我们的开发环境的编程语言和工具,并研究它们的ONVIF协议支持。 接下来,我们需要编写客户端程序代码。首先,我们需要实现设备发现功能,通过发送协议指定的消息,搜索网络中的ONVIF设备。一旦找到设备,我们就可以获取设备的信息,如设备地址、设备型号等。然后,我们可以向设备发送命令,如实时视频流请求、设备时间同步等。我们需要处理设备返回的响应消息,并根据协议规范处理各种结果。 最后,我们需要对开发客户端程序进行测试和调试。我们可以创建模拟的ONVIF设备,模拟设备的各种行为,并验证客户端程序的功能和性能。我们还可以使用一些专业的测试工具来检查客户端程序的兼容性和稳定性。 总而言之,在开发ONVIF协议网络摄像机客户端程序时,我们需要深入了解ONVIF协议,选择适合的开发平台和工具,编写代码实现协议的各种功能,并进行测试和调试。这个过程中需要耐心和细心,以确保开发出高质量的客户端程序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 63
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值