onvif学习笔记4:Windows环境使用gsoap生成onvif框架代码

因工作原因,被安排接手onvif,为了对其有个真正、切实、系统、认真、严谨的了解,就利用周末等业余时间来学习研究。
本文主要讲述在windows环境中使用gsoap生成onvif框架的代码,但不涉及框架代码的使用。由于实际真正使用的只有生成的代码文件,所以无论使用Linux还是Windows,都无所谓。

一、下载gsoap工具

gsoap下载地址为:https://sourceforge.net/projects/gsoap2/files/gSOAP/,截至本文编写时,最新版本为2.8.29,发布时间为2月24日。生成代码所需的wsdl2h.exe和soapcpp2.exe工具在gsoap\bin\win32目录。

二、生成onvif.h头文件

1、

wsdl2h是利用webservice描述语言(wsdl)生成头文件,下面的命令语句是将onvif官网上提供wsdl生成onvif.h头文件。注意typemap.dat为gsoap源码自带的文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
wsdl2h.exe -t ../gsoap/typemap.dat -o onvif.h -d \
http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl \
http://www.onvif.org/onvif/ver10/events/wsdl/event.wsdl http://www.onvif.org/onvif/ver10/display.wsdl http://www.onvif.org/onvif/ver10/deviceio.wsdl \
http://www.onvif.org/onvif/ver20/imaging/wsdl/imaging.wsdl http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl \
http://www.onvif.org/onvif/ver20/media/wsdl/media.wsdl http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl \
http://www.onvif.org/onvif/ver10/receiver.wsdl http://www.onvif.org/onvif/ver10/recording.wsdl \
http://www.onvif.org/onvif/ver10/search.wsdl http://www.onvif.org/onvif/ver10/replay.wsdl \
http://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdl http://www.onvif.org/onvif/ver10/analyticsdevice.wsdl \
http://www.onvif.org/onvif/ver10/schema/onvif.xsd http://www.onvif.org/ver10/actionengine.wsdl \
http://www.onvif.org/ver10/pacs/accesscontrol.wsdl http://www.onvif.org/ver10/pacs/doorcontrol.wsdl \
http://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl http://www.onvif.org/ver10/accessrules/wsdl/accessrules.wsdl \
http://www.onvif.org/ver10/credential/wsdl/credential.wsdl http://www.onvif.org/ver10/schedule/wsdl/schedule.wsdl \
http://www.onvif.org/ver10/pacs/types.xsd

(如果使用dos命令提示符,请把“\”去掉,使用mingw环境无须如此)

2、

生成的onvif.h文件中,在#import “wsa5.h”后面添加#import “wsse.h”,引入wsse.h头文件。

3、

将gsoap源码的was5.h(位于gsoap\import目录)的SOAP_ENV__Fault函数改名如下:

1
2
3
4
5
6
7
8
9
10
11
int SOAP_ENV__Fault_LateLee
( _QName faultcode,// SOAP 1.1
char *faultstring,// SOAP 1.1
char *faultactor,// SOAP 1.1
struct SOAP_ENV__Detail *detail,// SOAP 1.1
struct SOAP_ENV__Code *SOAP_ENV__Code,// SOAP 1.2
struct SOAP_ENV__Reason *SOAP_ENV__Reason,// SOAP 1.2
char *SOAP_ENV__Node,// SOAP 1.2
char *SOAP_ENV__Role,// SOAP 1.2
struct SOAP_ENV__Detail *SOAP_ENV__Detail,// SOAP 1.2
);

如果不修改,则会出现重定义错误,如下:

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

三、由onvif.h生成框架代码

命令如下:

1
soapcpp2.exe -i -S -I ../gsoap/import/ -I ../gsoap/ onvif.h

注:soapcpp2有许多参数,可用soapcpp2 -h查看。其中-c表示生成c格式代码(注:后缀名还是.cpp,但实现上是C),-c++表示生成c++格式代码(默认)。-x表示不产生xml文件(注:生成的xml可指导后续的开发工作,建议不使用“-x”参数)。-i表示生成代码的类继承soap结构体,-j表示类内部引用soap结构体。-I表示指定导入文件路径。-S表示生成服务端代码(文件名为xxxService.cpp),-C表示生成客户端代码(文件名为xxxProxy.cpp)。
上述命令表示生成C++代码,只产生服务端代码,使用继承soap的形式。另外生成xml文件。

四、生成代码简析

*.nsmap的文件为Namespace的定义,所有该后缀的文件内容是一样的。建议保留一份,并重新命名为namespace.h,这样更适合C++代码传统。值得注意的是,在生成框架的文件中,在需要使用命名空间,会在函数中定义和.nsmap中内容一致的的结构体,而不是引用`.nsmap`。这点在实际工作也可以参考。
soapXXXProxy.h/.cpp为client端代码文件。头文件类示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class SOAP_CMAC DeviceBindingProxy : public soap {
public:
/// Endpoint URL of service 'DeviceBindingProxy' (change as needed)
const char *soap_endpoint;
/// Variables globally declared in onvif.h, if any
/// Construct a proxy with new managing context
DeviceBindingProxy();
/// Copy constructor
DeviceBindingProxy(const DeviceBindingProxy& rhs);
/// Construct proxy given a managing context
DeviceBindingProxy(const struct soap&);
/// Constructor taking an endpoint URL
DeviceBindingProxy(const char *endpoint);
/// Constructor taking input and output mode flags for the new managing context
DeviceBindingProxy(soap_mode iomode);
/// Constructor taking endpoint URL and input and output mode flags for the new managing context
DeviceBindingProxy(const char *endpoint, soap_mode iomode);
/// Constructor taking input and output mode flags for the new managing context
DeviceBindingProxy(soap_mode imode, soap_mode omode);
/// Destructor deletes deserialized data and managing context
virtual ~DeviceBindingProxy();
}

soapxxxService.h/.cpp为server端代码文件。头文件类示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class SOAP_CMAC DeviceBindingService : public soap {
public:
/// Variables globally declared in onvif.h, if any
/// Construct a service with new managing context
DeviceBindingService();
/// Copy constructor
DeviceBindingService(const DeviceBindingService&);
/// Construct service given a managing context
DeviceBindingService(const struct soap&);
/// Constructor taking input+output mode flags for the new managing context
DeviceBindingService(soap_mode iomode);
/// Constructor taking input and output mode flags for the new managing context
DeviceBindingService(soap_mode imode, soap_mode omode);
/// Destructor deletes deserialized data and managing context
virtual ~DeviceBindingService();
/// Delete all deserialized data (with soap_destroy() and soap_end())
virtual void destroy();
/// Delete all deserialized data and reset to defaults
virtual void reset();
}

*.xml为xml命令协议格式文件,在调试时可做参考,下面为SetNTP命令的xml格式,注意,onvif的xml字符编码为UTF-8。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 <SOAP-ENV:Header>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<tds:SetNTP>
<tds:FromDHCP>false</tds:FromDHCP>
<tds:NTPManual>
<tt:Type>IPv4</tt:Type>
<tt:IPv4Address></tt:IPv4Address>
<tt:IPv6Address></tt:IPv6Address>
<tt:DNSname></tt:DNSname>
<tt:Extension>


</tt:Extension>
</tds:NTPManual>
</tds:SetNTP>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

根据本文命令生成的代码参见github仓库:https://github.com/latelee/onvif_fw_stl.git

李迟 2016.3.5 周六 时值两会,听政府工作报告