onvif 框架搭建
1.访问https://sourceforge.net/projects/gsoap2/,获得gsoap框架
2.打开gsoap-2.8\gsoap\bin目录,将soapcpp2.exe 和 wsdl2h.exe移动到新目录
3.生成 onvif.h 文件
wsdl2h -o onvif.h -s -t ./typemap.dat http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl http://www.onvif.org/onvif/ver10/event/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/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/network/wsdl/remotediscovery.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/ver10/actionengine.wsdl http://www.onvif.org/ver10/pacs/accesscontrol.wsdl http://www.onvif.org/ver10/pacs/doorcontrol.wsdl
文件下载可能很慢,可以先将wsdl文件下载下来,放到目录中生成。
会在wsdl2h.exe目录下生成 onvif.h 文件
4. 生成onvif框架
soapcpp2 -s -p p onvif.h -x -L -I./ -I./gsoap -I./import/ -I./custom -I./plugin 服务端生成
soapcpp2 -c -p p onvif.h -x -L -I./ -I./gsoap -I./import/ -I./custom -I./plugin 客户端生成
注意先将 gsoap-2.8\gsoap 目录下 custom import plugin 文件夹复制到 soapcpp2.exe 所在文件夹。
生成成功后目录下 pC.cpp pH.h pServer.cpp pStub.h 迁移到自己的工程目录,同时将 gsoap-2.8\gsoap\stdsoap2.cpp gsoap-2.8\gsoap\stdsoap2.h gsoap-2.8\gsoap\custom\duration.c gsoap-2.8\gsoap\custom\duration.h 一同放到目录中
5. 可以调用完成框架的建立了。
已完成的框架文件下载地址:https://download.youkuaiyun.com/download/lz201_xxj/14141924
鉴权:
1. 不想搭建openssl环境,直接下载了已编译的好的库文件,直接使用,可在下列地址下载:https://download.youkuaiyun.com/download/jsjtsty/10854630
2. 在前面生成的onvif.h的文件中加入 #import "wsse.h" 使鉴权可以被支持。
3. 重新生成onvif框架,跟前面的步骤相同。
4. 拷贝 gsoap-2.8\gsoap\dom.cpp gsoap-2.8\gsoap\plugin\mecevp.cpp gsoap-2.8\gsoap\plugin\smdevp.cpp gsoap-2.8\gsoap\plugin\threads.cpp gsoap-2.8\gsoap\plugin\wsaapi.cpp gsoap-2.8\gsoap\plugin\wsseapi.cpp 文件到工程目录,同时将openssl库文件和头文件加入工程目录,环境搭建完成。
5. 编译后会出现一些问题,主要是CC++混合编译,我的做法是将所有的c文件强制命名成CPP文件,同时不使用预编译头。有些函数没有实体,比如soap_default_xsd__dateTime等,直接建一个空函数。在预处理器中添加WITH_DOM 和 WITH_OPENSSL,使能鉴权功能。
6. 编译通过后就是使用问题了,在客户端中直接调用 soap_wsse_add_UsernameTokenDigest 进行鉴权,注意需要在每次访问服务端前调用。在服务端中 通过soap_wsse_get_Username 和 soap_wsse_verify_Password 验证客户端发送的用户名和密码是否与服务端的匹配,将这两个函数封装到一个函数中同时判断,在需要鉴权的soap处理函数中位置加入这两个函数,未通过返回0即可。
以上功能已通过海康摄像机和ONVIF Device Manager软件分别对服务端和客户端功能进行了验证。
wsdl2h用作wsdl和.h文件的转换。soapcpp2用头文件生成客户端/服务端等开发需要的h和cpp文件。
1:wsdl2h指令汇总
-o filename.h 将wsdl转化为filename.h头文件。
-s 不生成STL代码
-c 生成纯C风格的头文件,这将去除C++的一些特性
-n name 使用name代替默认前缀ns
-t filename.dat 使用filename.dat代替默认的typemap.dat文件
-zX 兼容之前的X版本
2:soapcpp2
-i 生成server的proxy和object,这种object继承于soap struct。
-j 和-i类似,区别在于生成的代理类不继承于soap struct,而是包含了包含了一个soap结构的指针。此种方式生存的代理类便于互相通信
-c 仅生成客户端client代码
-s 仅生成服务端server代码
-x 不生成xml文件。不用此项的话,将对头文件中定义的每个operation生成一个描述性的xml文件
-L 不生成soapClientLib文件和soapServerLib文件
-p name 修改文件名前缀,代替soap
-q name 指定代理类和对象使用的名空间name,包含文件名前缀
注:
1. 在服务端接收鉴权等信息时,报 wsse:Security 错误,内部发现是服务端 SOAP_SYNTAX_ERROR 错误,导致客户端错误,表现在无法进行鉴权,海康相机无此问题,自己的服务端有这个问题,经过搜索(感谢 https://blog.youkuaiyun.com/u012084827/article/details/45157923 快活林高老大)提供的解决办法,按以下方法修正后解决问题。
soap_s2byte(struct soap *soap, const char *s, char *p)
{ if (s)
{ long n;
char *r;
n = soap_strtol(s, &r, 10);
if (s == r || *r || n < -128 || n > 127)
{
soap->error = SOAP_TYPE;
}
*p = (char)n;
}
return soap->error;
}
soap_s2byte这个函数调用soap_strtol进行转换,s是输入字符串,p指向转换后的单字节。但是对于s=“”空字符串无法转换成功,引起s==r成立,导致错误返回SOAP_TYPE。 看起来好像是gsoap的一个bug。修改方法是去除s==r的判断条件,避免报告错误。
if ( n < -128 || n > 127)
{
soap->error = SOAP_TYPE;
}