2.解压gsoap_2.8.109.zip
3.进入gsoap2.8/gsoap/bin/win64目录
a.拷贝gsoap/wsdl/目录下的typemap.dat文件到当前目录
b.创建脚本auto_code_h_c++11.bat
@ECHO OFF CD /D "%~dp0" mkdir output wsdl2h.exe -o output\onvif.h -c++11 -s -t .\typemap.dat http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.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/ver10/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/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/onvif/ver10/schema/onvif.xsd http://www.onvif.org/ver10/actionengine.wsdl @ECHO &PAUSE
c.创建脚本auto_code_cpp_c++11.bat
@ECHO OFF CD /D "%~dp0" mkdir output soapcpp2.exe -2 -c++11 -j -x output\onvif.h -I%CD%/../../../../gsoap-2.8/gsoap;%CD%/../../../../gsoap-2.8/gsoap/import; -d output @ECHO &PAUSE
d.创建脚本auto_code_client_c++11.bat
@ECHO OFF CD /D "%~dp0" mkdir output soapcpp2 -a -x -L -pwsdd -d output -I%CD%/../../../../gsoap-2.8/gsoap/import; %CD%/../../../../gsoap-2.8/gsoap/import/wsdd5.h @ECHO &PAUSE
4.运行脚本auto_code_h_c++11.bat
在output目录生成onvif.h文件
在onvif.h中添加#import "wsse.h"(鉴权使用)
5.运行脚本auto_code_cpp_c++11.bat
在output目录生成许多文件:
6.运行脚本auto_code_client_c++11.bat
在output目录生成许多文件:
7.使用方法:
新建gsoap-lib目录,三个子目录plugin、custom、stub
拷贝6步骤output目录下所有文件到stub目录。
拷贝
dom.cpp
stdsoap2.h stdsoap2.cpp
到gsoap-lib目录。
拷贝
chrono_duration.cpp chrono_time_point.cpp duration.c struct_timeval.c
chrono_duration.h chrono_time_point.h duration.h struct_timeval.h
到gsoap-lib目录(将后缀.c全部修改为.cpp)。
拷贝
mecevp.c smdevp.c threads.c wsaapi.c wsseapi.c wsse2api.c
mecevp.h smdevp.h threads.h wsaapi.h wsseapi.h wsse2api.c
到gsoap-lib目录(将后缀.c全部修改为.cpp)。
8.编译
编译时添加标志:
-DWITH_NONAMESPACES
-DWITH_OPENSSL
-DWITH_DOM
9.头文件引入
#include <stdsoap2.h>
#include <wsaapi.h>
#include <wsddStub.h>
#include <wsseapi.h>
#include <wsdd.nsmap>//注意:如果编译提示命名空间多处定义,可以注释此行再次编译
#include <soapStub.h>
#include <httpda.h>
#include <soapPTZBindingProxy.h>
#include <soapDeviceBindingProxy.h>
#include <soapMediaBindingProxy.h>
FAQ常见问题及解决
问题1及解决:
wsa5.h(288): **ERROR**: service operation name clash: struct/class 'SOAP_ENV__Fault' already declared at wsa.h:273
则修改wsa5.h中的SOAP_ENV__Fault 为 SOAP_ENV__Fault_WSA5即可。
问题2及解决:
error LNK2001: unresolved external symbol namespaces
则引入头文件#include <wsdd.nsmap>(根据你实际的项目nsmap文件修改即可)
问题3及解决:
返回400/401,Bad Request/Unauthorized
鉴权方式问题,请参阅另一篇文章《onvif 鉴权最佳实践》
问题4及解决:
设备发现加入时总会提示namespaces已经重复定义
解决方法:如果出现问题2错误,则自行定义.
//#include <wsdd.nsmap> 注释此行 int OnvifMgr::DeviceDiscovery() { //切记,变量名不可为namespaces. SOAP_NMAC struct Namespace discovery_namespaces[] = { { "SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://schemas.xmlsoap.org/soap/envelope/", NULL }, { "SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://schemas.xmlsoap.org/soap/encoding/", NULL }, { "xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL }, { "xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL }, { "wsa", "http://schemas.xmlsoap.org/ws/2004/08/addressing", "http://www.w3.org/2005/08/addressing", NULL }, { "wsdd", "http://schemas.xmlsoap.org/ws/2005/04/discovery", NULL, NULL }, { "chan", "http://schemas.microsoft.com/ws/2005/02/duplex", NULL, NULL }, { "c14n", "http://www.w3.org/2001/10/xml-exc-c14n#", NULL, NULL }, { "ds", "http://www.w3.org/2000/09/xmldsig#", NULL, NULL }, { "saml1", "urn:oasis:names:tc:SAML:1.0:assertion", NULL, NULL }, { "saml2", "urn:oasis:names:tc:SAML:2.0:assertion", NULL, NULL }, { "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", NULL, NULL }, { "xenc", "http://www.w3.org/2001/04/xmlenc#", NULL, NULL }, { "wsc", "http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512", "http://schemas.xmlsoap.org/ws/2005/02/sc", NULL }, { "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd", NULL }, { "wsdd10", "http://tempuri.org/wsdd10.xsd", NULL, NULL }, { "wsa5", "http://www.w3.org/2005/08/addressing", "http://schemas.xmlsoap.org/ws/2004/08/addressing", NULL }, { "ns1", "http://www.onvif.org/ver20/analytics/humanface", NULL, NULL }, { "ns2", "http://www.onvif.org/ver20/analytics/humanbody", NULL, NULL }, { "xmime", "http://tempuri.org/xmime.xsd", NULL, NULL }, { "xop", "http://www.w3.org/2004/08/xop/include", NULL, NULL }, { "tt", "http://www.onvif.org/ver10/schema", NULL, NULL }, { "wsrfbf", "http://docs.oasis-open.org/wsrf/bf-2", NULL, NULL }, { "wstop", "http://docs.oasis-open.org/wsn/t-1", NULL, NULL }, { "wsrfr", "http://docs.oasis-open.org/wsrf/r-2", NULL, NULL }, { "ns3", "http://www.onvif.org/ver10/actionengine/wsdl", NULL, NULL }, { "tad", "http://www.onvif.org/ver10/analyticsdevice/wsdl", NULL, NULL }, { "tan", "http://www.onvif.org/ver20/analytics/wsdl", NULL, NULL }, { "tdn", "http://www.onvif.org/ver10/network/wsdl", NULL, NULL }, { "tds", "http://www.onvif.org/ver10/device/wsdl", NULL, NULL }, { "tev", "http://www.onvif.org/ver10/events/wsdl", NULL, NULL }, { "wsnt", "http://docs.oasis-open.org/wsn/b-2", NULL, NULL }, { "timg", "http://www.onvif.org/ver20/imaging/wsdl", NULL, NULL }, { "tls", "http://www.onvif.org/ver10/display/wsdl", NULL, NULL }, { "tmd", "http://www.onvif.org/ver10/deviceIO/wsdl", NULL, NULL }, { "tptz", "http://www.onvif.org/ver20/ptz/wsdl", NULL, NULL }, { "trc", "http://www.onvif.org/ver10/recording/wsdl", NULL, NULL }, { "trp", "http://www.onvif.org/ver10/replay/wsdl", NULL, NULL }, { "trt", "http://www.onvif.org/ver10/media/wsdl", NULL, NULL }, { "trv", "http://www.onvif.org/ver10/receiver/wsdl", NULL, NULL }, { "tse", "http://www.onvif.org/ver10/search/wsdl", NULL, NULL }, { NULL, NULL, NULL, NULL} }; // 宏值定义 const char* MULTICAST_ADDRESS = "soap.udp://239.255.255.250:3702"; // 组播IP:239.255.255.250,Onvif服务端监听的端口为3702 int result = 0; wsdd__ProbeType req; struct __wsdd__ProbeMatches resp; wsdd__ScopesType sScope; struct SOAP_ENV__Header header; std::unordered_map<std::string, Camera> camMap = {}; struct soap* soap; soap = soap_new(); if (NULL == soap) { DEBUGPRINT("sopa new error\r\n"); return -1; } soap->recv_timeout = 10; soap_set_namespaces(soap, discovery_namespaces); soap_default_SOAP_ENV__Header(soap, &header); header.wsa__MessageID = (char*)soap_wsa_rand_uuid(soap); header.wsa__To = (char*)"urn:schemas-xmlsoap-org:ws:2005:04:discovery"; header.wsa__Action = (char*)"http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe"; soap->header = &header; soap_default_wsdd__ScopesType(soap, &sScope); sScope.__item = (char*)""; soap_default_wsdd__ProbeType(soap, &req); req.Scopes = &sScope; req.Types = (char*)"dn:NetworkVideoTransmitter"; int i = 0; result = soap_send___wsdd__Probe(soap, MULTICAST_ADDRESS, NULL, &req); while (result == SOAP_OK) { result = soap_recv___wsdd__ProbeMatches(soap, &resp); if (result == SOAP_OK) { if (soap->error) { DEBUGPRINT("soap error 1: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap)); result = soap->error; } else { try { DEBUGPRINT("*********************************************\r\n"); if (soap->header->wsa__MessageID) { DEBUGPRINT("MessageID : %s\r\n", soap->header->wsa__MessageID); } if (soap->header->wsa__RelatesTo && soap->header->wsa__RelatesTo->__item) { DEBUGPRINT("RelatesTo : %s\r\n", soap->header->wsa__RelatesTo->__item); } if (soap->header->wsa__To) { DEBUGPRINT("To : %s\r\n", soap->header->wsa__To); } if (soap->header->wsa__Action) { DEBUGPRINT("Action : %s\r\n", soap->header->wsa__Action); } for (i = 0; i < resp.wsdd__ProbeMatches->__sizeProbeMatch; i++) { try { if (resp.wsdd__ProbeMatches != nullptr) { DEBUGPRINT("__sizeProbeMatch : %d\r\n", resp.wsdd__ProbeMatches->__sizeProbeMatch); DEBUGPRINT("wsa__EndpointReference : %p\r\n", &resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference); DEBUGPRINT("Target EP Address : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address); DEBUGPRINT("Target Type : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Types); DEBUGPRINT("Target Service Address : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->XAddrs); DEBUGPRINT("Target Metadata Version : %d\r\n", resp.wsdd__ProbeMatches->ProbeMatch->MetadataVersion); if (resp.wsdd__ProbeMatches->ProbeMatch->Scopes != nullptr) { DEBUGPRINT("Target Scopes Address : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Scopes->__item); } Camera cam = {}; if (resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address != nullptr && *resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address) { cam.uuid = resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address; if (resp.wsdd__ProbeMatches->ProbeMatch->Types && *resp.wsdd__ProbeMatches->ProbeMatch->Types && std::string(resp.wsdd__ProbeMatches->ProbeMatch->Types).find(' ') != std::string::npos) { cam.url = std::string(resp.wsdd__ProbeMatches->ProbeMatch->Types).substr(0, std::string(resp.wsdd__ProbeMatches->ProbeMatch->Types).find(' ')); } camMap.emplace(std::unordered_map<std::string, Camera>::value_type(cam.uuid, cam)); } } } catch (const std::exception& e) { DEBUGPRINT("%s\n", e.what()); } } } catch (const std::exception& e) { DEBUGPRINT("%s\n", e.what()); } } } else if (soap->error) { DEBUGPRINT("[%d] soap error 2: %d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap)); result = soap->error; } } soap_destroy(soap); soap_end(soap); soap_free(soap); DEBUGPRINT("[%d] discover finish !\n", __LINE__); if (!camMap.empty()) { std::lock_guard<std::mutex> lock(m_camLocker); for (auto it : camMap) { m_camMap.emplace(it); } } return 0; }