ONVIF开发总结.docx
《ONVIF开发总结.docx》由会员分享,可在线阅读,更多相关《ONVIF开发总结.docx(16页珍藏版)》请在冰豆网上搜索。
ONVIF开发总结
ONVIF开发经验总结
一、利用gsoap2.8.14生成Onvif相关源代码
1.生成onvif.h头文件的方法
产生头文件有两种方法:
链接网络生成和本地生成。
1)wsdl2h相关命令参数
-c产生c语言的代码,否则产生C++
-s不使用STL代码
-t指定typemap.dat文件
-o指定生成的头文件名
2)链接网络生成
●将wsdl2.exe和typemap.dat文件放入同一个文件夹
●利用cmd或批处理执行以下dos命令:
wsdl2h.exe-c-s-ttypemap.dat-oonvif.h
3)下载到本地生成
●从ONVIF官网上把相关的WSDL文档下载到本地,下载地址(详细参见备注说明),此外还需下载样式表,下载地址见WSDL文档中的schemaLocation。
●将wsdl2.exe、typemap.dath、WSDL文档和样式表放入同一文件夹中。
●将相关WSDL文档中的样式表引入路径(schemaLocation)修改为本地实际地址,如:
event.wsdl中schemaLocation="修改为schemaLocation=ws-addr.xsd
●利用cmd或批处理执行以下命令
wsdl2h.exe-c-s-ttypemap.dat-oonvif.hremotediscovery.wsdldevicemgmt.wsdlanalytics.wsdlanalyticsdevice.wsdlmedia.wsdldeviceio.wsdldisplay.wsdlevent.wsdlimaging.wsdlrecording.wsdlreplay.wsdlsearch.wsdlreceiver.wsdlptz.wsdl
4)备注说明
●wsdl2.exe位于gsoap_2.8.14\gsoap-2.8\gsoap\bin
●typemap.dat位于gsoap_2.8.14\gsoap-2.8\gsoap
●wsdl下载地址:
●各url之间用空格隔开
●typemap.dat不需要修改
●链接网络生成方法的优点是不用考虑以上文件对其它文件的依赖关系,不用修改引入路径。
该方法的缺点跟网速有关,因此中途可能会中断,如果超过5分钟未生成,可重新执行命令,通过代理上网则无法生成,不推荐用此方法。
●下载本地生成方法的优缺点和链接网络方法生成相反,代理网推荐使用此方法。
2.生成onvif源代码
1)整理相关的文件
把刚生成的onvif.h与soapcpp2.exe、import和custom放入同一文件夹,其中:
soapcpp2.exe位于gsoap_2.8.14\gsoap-2.8\gsoap\bin
import位于gsoap_2.8.14\gsoap-2.8\gsoap
custom位于gsoap_2.8.14\gsoap-2.8\gsoap
2)通过以下命令生成相关源文件
soapcpp2.exe-2–convif.h-Iimport
3)Soapcpp2相关命令参数
-2采用SOAP1.2,
-x不产生xml文件(不推荐使用此命令,因为xml文档很有用)
-I为引入路径
-C只产生客户端代码(注意:
C是大写)
4)备注说明
●需要在onvif.h中加入#import"wsse.h,用来做安全验证
●需要将import目录下的wsa5.h以下部分注释掉,否则编译时会报soap_xxxx_SOAP_ENV__Fault()函数重复定义。
intSOAP_ENV__Fault
(_QNamefaultcode,//SOAP1.1
char*faultstring,//SOAP1.1
char*faultactor,//SOAP1.1
structSOAP_ENV__Detail*detail,//SOAP1.1
structSOAP_ENV__Code*SOAP_ENV__Code,//SOAP1.2
structSOAP_ENV__Reason*SOAP_ENV__Reason,//SOAP1.2
char*SOAP_ENV__Node,//SOAP1.2
char*SOAP_ENV__Role,//SOAP1.2
structSOAP_ENV__Detail*SOAP_ENV__Detail,//SOAP1.2
void);
3.利用gsoap2.8.8生成源代码和gsoap2.8.14生成的差异
利用gsoap2.8.8生成源代码方法跟gsoap2.8.14基本一致,但需注意以下区别:
1)typemap.dat文件中需要添加相关信息
tds=""
tev=""
tls=""
tmd=""
timg=""
trt=""
tptz=""
trv=""
trc=""
tse=""
trp=""
tan=""
tad=""
tdn=""
tt=""
#OASISrecommendedprefixes
wsnt=""
wsntw=""
wsrfbf=""
wsrfr=""
wsrfrw=""
wstop=""
#WS-Discovery1.0remapping
wsdd10__HelloType=|wsdd__HelloType
wsdd10__ByeType=|wsdd__ByeType
wsdd10__ProbeType=|wsdd__ProbeType
wsdd10__ProbeMatchesType=|wsdd__ProbeMatchesType
wsdd10__ProbeMatchType=|wsdd__ProbeMatchType
wsdd10__ResolveType=|wsdd__ResolveType
wsdd10__ResolveMatchesType=|wsdd__ResolveMatchesType
wsdd10__ResolveMatchType=|wsdd__ResolveMatchType
#SOAP-ENVmapping
SOAP_ENV__Envelope=structSOAP_ENV__Envelope{structSOAP_ENV__Header*SOAP_ENV__Header;_XMLSOAP_ENV__Body;};|structSOAP_ENV__Envelope
SOAP_ENV__Header=|structSOAP_ENV__Header
SOAP_ENV__Fault=|structSOAP_ENV__Fault
SOAP_ENV__Detail=|structSOAP_ENV__Detail
SOAP_ENV__Code=|structSOAP_ENV__Code
SOAP_ENV__Subcode=|structSOAP_ENV__Subcode
SOAP_ENV__Reason=|structSOAP_ENV__Reason
2)wsa5.h中无SOAP_ENV__Fault函数
由于wsa5.h中没有SOAP_ENV__Fault因此不会产生代码重复,因此不用注释。
二、新建工程,调试代码
1.新建一个项目
将上面生成的soapH.h、soapStub.h、wsdd.nsmap、soapC.c、soapClient.c,还有位于gsoap-2.8\gsoap的:
stdsoap2.c、stdsoap2.h和位于\custom中的:
duration.c放入工程中,然后编写main函数,调试代码。
2.文件主要功能说明
wsdd.nsmap名空间定义,服务器端与客户端都要包含它,里面有很多,都是
相同的,只需导入一个进入工程就行
stdsoap2.hHeader_leofstdsoap2.cppruntimelibrary
stdsoap2.cRuntimeClibrarywithXMLparserandrun-timesupportroutinessoapStub.hsoapH.h//Mainheaderbeincludedbyallclientandservicesources
soapC.c//Serializersanddeserializersforthespecfieddatastructures
soapClient.c//Clientstubroutinesforremoteoperations
soapStub.hAmodi_edandannotatedheaderfromtheinputheaderfile
三、设备发现main函数说明
#include
#include"wsdd.nsmap"
#include"soapH.h"
usingnamespacestd;
intmain()
{
/*****声明变量***********/
structsoap*soap;//soap环境变量
structwsdd__ProbeTypereq;//客户端发送的Probe
struct__wsdd__ProbeMatchesresp;//服务端回的Probematchs
structwsdd__ScopesTypesScope;//Probe里面的范围
structSOAP_ENV__Headerheader;//SOAP的头
intresult=0;//返回值
intcount=0;//获得的设信息备个数
/**获取guid(windows下叫guid,linux下叫uuid),格式为urn:
uuid:
8-4-4-4-12,由系统随机产生**/
staticcharbuf[64]={0};//用来保存guid号
GUIDguid;/*声明guid为GUID结构体变量,包含4个变量,分别是
unsignedlongData1;
unsignedshortData2;
unsignedshortData3;
unsignedcharData4[8];
*/
if(S_OK==CoCreateGuid(&guid))//如果guid生成成功,则将其转为字符串,保存在buf中
{
_snprintf(buf,sizeof(buf)
"urn:
uuid:
%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X"
guid.Data1
guid.Data2
guid.Data3
guid.Data4[0],guid.Data4[1]
guid.Data4[2],guid.Data4[3],guid.Data4[4],guid.Data4[5]
guid.Data4[6],guid.Data4[7]
);
}
soap=soap_new();//初始化soap
if(soap==NULL)
{
return-1;
}
soap_set_namespaces(soap,namespaces);//设置命名空间
soap->recv_timeout=5;//设置接收Probematchs时间,超过5秒钟没有数据就退出
soap_default_SOAP_ENV__Header(soap,&header);//将header设置为soap消息的头属性
/*****给头赋值******/
header.wsa__MessageID=buf;
header.wsa__To="urn:
schemas-xmlsoap-org:
ws:
2005:
04:
discovery";
header.wsa__Action="";
soap->header=&header;
/*设置所需寻找设备的类型和范围,二者至少设定一个,否则可能收到非ONVIF设备,出现异常*/
soap_default_wsdd__ScopesType(soap,&sScope);
sScope.__item="onvif:
//";//设置所需设备的sScope
soap_default_wsdd__ProbeType(soap,&req);
req.Scopes=&sScope;
req.Types="tdn:
NetworkVideoTransmitter";
/*设置所需设备的类型,tdn为命名空间前缀,为wsdd.nsmap文件中{"tdn",""}的tdn,如过不是tdn,而是其它,如ns1这里也要随之改为ns1*/
//通过组播发送Probe探针,发送成功返回0,否则-1
result=soap_send___wsdd__Probe(soap,"soap.udp:
//239.255.255.250:
3702",NULL,&req);
if(result==-1)
{
cout<<"soaperror:
"<error<<<"---"<}else
{
do{
result=soap_recv___wsdd__ProbeMatches(soap,&resp);
//接收ProbeMatches,成功返回0,否则-1
if(result==-1)
{
cout<<"共发现"<cout<<"soaperror:
"<error<<<"---"<break;
}else
{
count++;
cout<<"========================================="<cout<<"UUID:
"<<""<ProbeMatch->
wsa__EndpointReference.Address<cout<<"Type:
"<<""<ProbeMatch->Types<cout<<"Scopes:
"<<""<
ProbeMatch->Scopes->__item<cout<<"DeviceServiceAddress:
"<<""<
ProbeMatch->XAddrs<cout<<"MetadataVersion:
"<<""<
ProbeMatch->MetadataVersion<}
}while
(1);
}
/********清除变量************/
soap_destroy(soap);//removedeserializedclassinstances(C++only)
soap_end(soap);//cleanupandremovedeserializeddata
soap_done(soap);
returnresult;
}
四、调试过程遇到的问题和注意事项
1.出现如下语法错误:
errorC2143:
语法错误:
缺少“{”(在“:
”的前面)
errorC2059:
语法错误:
“:
”
errorC2143:
语法错误:
缺少“{”(在“:
”的前面)
需要将工程中的.c文件改成.cpp文件即可。
2.无法解析的外部命令错误soap_check_faultsubcode
在stdsoap2.h中声明的soap_check_faultsubcode(structsoap*soap)函数在soapC.cpp中未实现,可在soapC.cpp中添加如下实现:
SOAP_FMAC3constchar*SOAP_FMAC4soap_check_faultsubcode(structsoap*soap)
{
soap_fault(soap);
if(soap->version==2)
{
if(soap->fault->SOAP_ENV__Code&&soap->fault->SOAP_ENV__Code->SOAP_ENV__Subcode&&soap->fault->SOAP_ENV__Code->SOAP_ENV__Subcode)
returnsoap->fault->SOAP_ENV__Code->SOAP_ENV__Subcode->SOAP_ENV__Value;
returnNULL;
}
returnsoap->fault->faultcode;
}
3.无法解析的外部命令错误soap_check_faultdetail
在stdsoap2.h中声明的soap_check_faultdetail(structsoap*soap)函数在soapC.cpp中未实现,可在soapC.cpp中添加如下实现:
SOAP_FMAC3constchar*SOAP_FMAC4soap_check_faultdetail(structsoap*soap)
{
soap_fault(soap);
if(soap->version==2&&soap->fault->SOAP_ENV__Detail)
returnsoap->fault->SOAP_ENV__Detail->__any;
if(soap->fault->detail)
returnsoap->fault->detail->__any;
returnNULL;
}
4.出现无法解析的外部符号_soap_in_xsd__duration
无法解析的外部符号_soap_in_xsd__duration,该符号在函数_soap_getelement中被引用soapC.obj:
errorLNK2019:
无法解析的外部符号_soap_out_xsd__duration,该符号在函数_soap_putelement中被引用
soapC.obj:
errorLNK2019:
无法解析的外部符号_soap_default_xsd__duration,该符号在函数_soap_default__tse__FindMetadata中被引用
需要将\custom文件夹下面的duration.h和duration.c导入工程中。
5.在VS中出现fatalerrorC1128:
节数超过对象文件格式限制:
请使用/bigobj进行编译的错误
这是由于源代码文件太大的原因,需添加选项/bigobj,在项目属性->C/C++->命令行的附加选项中添加/bigobj。
6.如果是调用soap_call_XXXX_Probe()来实现设备发现时不能发现所有onvif设备
该函数实现过程中只有一次接收过程,所以无法发现所有的设备的问题。
如果使用该函数,还需要对函数的实现做以下更改:
函数的接收部分,将原来的XXXX:
Response该为YYYY:
ProbeMatches,
其中XXXX是.nsmap文件中"所对应的命名空间前缀,YYYY与后面YYYY:
ProbeMatchesType中的前缀相同,都是所对应的命名空间前缀名。
7.抓包实验问题
利用gsoap生成的wsdd.namsp如下:
#include"soapH.h"
SOAP_NMACstructNamespacenamespaces[]=
{
{"SOAP-ENV","","*/soap-envelope",NULL},
{"SOAP-ENC","","*/soap-encoding",NULL},
{"xsi","","*/XMLSchema-instance",NULL},
{"xsd","","*/XMLSchema",NULL},
{"wsa","",NULL,NULL},
{"wsdd","",NULL,NULL},
{"chan","",NULL,NULL},
{"wsa5","","",NULL},
{"xmime","",NULL,NULL},
{"xop","",NULL,NULL},
{"tt","",NULL,NULL},
{"wsrfbf","",NULL,NULL},
{"wstop","",NULL,NULL},
{"wsrfr","",NULL,NULL},
{"tad","",NULL,NULL},
{"tan","",NULL,NULL},
{"tdn","",NULL,NULL},
{"tds","",NULL,NULL},
{"tev","",NULL,NULL},
{"wsnt","",NULL,NULL},
{"timg","",NULL,NULL},
{"tls","",NULL,NULL},
{"tmd","",NULL,NULL},
{"tptz","",NULL,NULL},
{"trc","",NULL,NULL},
{"trp","",NULL,NULL},
{"trt","",NULL,NULL},
{"trv","",NULL,NULL},
{"tse","",NULL,NULL},
{NULL,NULL,NULL,NULL}
};
1)通过编写面函数之后,调试运行结果如下:
其中为本地模拟的设备
通过抓包工具获得信息如下: