gsop工具gsop定义为一个工具,他的作用是根据xml等的配置文件生成符合onvif协议的webserver的c/c++源代码
The gSOAP toolkit is a C and C++ software development toolkit for SOAP and REST XML Web services and generic C/C++ XML data bindings. The toolkit analyzes WSDLs and XML schemas (separately or as a combined set) and maps the XML schema types and the SOAP/REST XML messaging protocols to easy-to-use and efficient C and C++ code. It also supports exposing (legacy) C and C++ applications as XML Web services by auto-generating XML serialization code and WSDL specifications. Or you can simply use it to automatically convert XML to/from C and C++ data. The toolkit supports options to generate pure ANSI C or C++ with or without STL.
gsoap的主要用途是生产onvif协议的平台无关c代码,首先来一张使用原理图:
分析图片,用户输入WSDL ,gsoap自动生成C/C++ Source Code Files,而wsdl文件就是符合onvif协议的配置文件,可以使用下面的wsdl资源来在线生成。
gsoap如何根据WSDL生成c代码?
gsoap提供两个编译工具
wsdl2h -o outfile.h infile.wsdl
wsdl2h -o XMethodsQuery.h http://www.xmethods.net/wsdl/query.wsdl
wsdl->h有两种方式,在线和离线,任选其一
soapcpp2 -c outfile.h
在使用soapcpp2工具,即可生成对应的webserver代码
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/media/wsdl/media.wsdl
http://www.onvif.org/onvif/ver10/recording.wsdl
http://www.onvif.org/onvif/ver10/display.wsdl
http://www.onvif.org/onvi f/ver10/receiver.wsdl
http://www.onvif.org/onvif/ver10/deviceio.wsdl
http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl
http://www.onvif.org/onvif/ver10/search.wsdl
http://www.onvif.org/onvif/ver10/schema/onvif.xsd
https://www.onvif.org/ver20/media/wsdl/media.wsdl
1.下载gsoap源码
2.编译gsoap工具
cd gsoap
./configure
make
make install
3.生成discover的onvif.h
root@zjy-T440:~/software/gsoap-2.8/mydiscover# ../gsoap/wsdl/wsdl2h -o onvif.h -c -s -k -t ./typemap.dat https://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl
Saving onvif.h
** The gSOAP WSDL/WADL/XSD processor for C and C++, wsdl2h release 2.8.96
** Copyright (C) 2000-2019 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., [email protected]
** ----------------------------------------------------------------------------
Reading type definitions from type map "./typemap.dat"
Connecting to 'https://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl' to retrieve WSDL/WADL or XSD...
connected, receiving...
Done reading 'https://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.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 onvif.h
root@zjy-T440:~/software/gsoap-2.8/mydiscover#
4.根据onvif.h生成源码框架
root@zjy-T440:~/software/gsoap-2.8/mydiscover# ../gsoap/src/soapcpp2 -c onvif.h -x -d ./ -I ../gsoap/import -I ../gsoap/
** The gSOAP code generator for C and C++, soapcpp2 release 2.8.96
** Copyright (C) 2000-2019, 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., [email protected]
** ----------------------------------------------------------------------------
Using project directory path: ./
Saving ./soapStub.h annotated copy of the source interface header file
Saving ./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 ./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 ./RemoteDiscoveryBinding.nsmap namespace mapping table
Saving ./soapClient.c client call stub functions
Saving ./soapClientLib.c client stubs with serializers (use only for libs)
Saving ./soapServer.c server request dispatcher
Saving ./soapServerLib.c server request dispatcher with serializers (use only for libs)
Saving ./soapC.c serialization functions
Compilation successful
root@zjy-T440:~/software/gsoap-2.8/mydiscover#
root@zjy-T440:~/software/gsoap-2.8/mydiscover# ls
onvif.h soapC.c soapClientLib.c soapServer.c soapStub.h wsdd.nsmap
RemoteDiscoveryBinding.nsmap soapClient.c soapH.h soapServerLib.c typemap.dat
root@zjy-T440:~/software/gsoap-2.8/mydiscover#
5.拷贝相关代码到工程
一些框架代码可能会用得到
root@zjy-T440:~/software/gsoap-2.8/mydiscover# ls ../gsoap
bin libgsoap.a libgsoapck_a-dom.o Makefile stdsoap2_ck.c typemap.dat
custom libgsoap++.a libgsoapck___a-stdsoap2_ck_cpp.o Makefile.am stdsoap2_ck_cpp.cpp uddi2
doc libgsoap___a-dom_cpp.o libgsoapck_a-stdsoap2_ck.o Makefile.in stdsoap2.cpp VisualStudio2005
dom.c libgsoap_a-dom.o libgsoapssl.a mod_gsoap stdsoap2_cpp.cpp WS
dom.cpp libgsoap___a-stdsoap2_cpp.o libgsoapssl++.a Palm stdsoap2.h wsdl
dom_cpp.cpp libgsoap_a-stdsoap2.o libgsoapssl___a-dom_cpp.o plugin stdsoap2_ssl.c
extras libgsoapck.a libgsoapssl_a-dom.o samples stdsoap2_ssl_cpp.cpp
import libgsoapck++.a libgsoapssl___a-stdsoap2_ssl_cpp.o src Symbian
ios_plugin libgsoapck___a-dom_cpp.o libgsoapssl_a-stdsoap2_ssl.o stdsoap2.c TandemNonStop
root@zjy-T440:~/software/gsoap-2.8/mydiscover#
root@zjy-T440:~/software/gsoap-2.8/mydiscover# cp ../gsoap/dom.c ./
root@zjy-T440:~/software/gsoap-2.8/mydiscover# cp ../gsoap/stdsoap2.* ./
root@zjy-T440:~/software/gsoap-2.8/mydiscover# cp ../gsoap/custom/duration. ./
duration.c duration.h
root@zjy-T440:~/software/gsoap-2.8/mydiscover# cp ../gsoap/custom/duration.* ./
root@zjy-T440:~/software/gsoap-2.8/mydiscover# cp ../gsoap/plugin/mecevp.* ./
root@zjy-T440:~/software/gsoap-2.8/mydiscover# cp ../gsoap/plugin/smdevp.* ./
root@zjy-T440:~/software/gsoap-2.8/mydiscover# cp ../gsoap/plugin/threads.* ./
root@zjy-T440:~/software/gsoap-2.8/mydiscover# cp ../gsoap/plugin/wsaapi.* ./
root@zjy-T440:~/software/gsoap-2.8/mydiscover# cp ../gsoap/plugin/wsseapi.* ./
root@zjy-T440:~/software/gsoap-2.8/mydiscover# cp ../gsoap/plugin/wsddapi.* ./
root@zjy-T440:~/software/gsoap-2.8/mydiscover#
6、生成main.c 文件
#include
#include
#include
#include "soapH.h"
#include "wsdd.nsmap"
#include "soapStub.h"
SOAP_FMAC5 int SOAP_FMAC6 soap_send___wsdd__ProbeMatches(struct soap *soap, const char *soap_endpoint, const char *soap_action, struct wsdd__ProbeMatchesType *wsdd__ProbeMatches)
{ struct __wsdd__ProbeMatches soap_tmp___wsdd__ProbeMatches;
if (soap_action == NULL)
soap_action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/ProbeMatches";
soap_tmp___wsdd__ProbeMatches.wsdd__ProbeMatches = wsdd__ProbeMatches;
soap_begin(soap);
soap->encodingStyle = NULL; /* use SOAP literal style */
soap_serializeheader(soap);
soap_serialize___wsdd__ProbeMatches(soap, &soap_tmp___wsdd__ProbeMatches);
if (soap_begin_count(soap))
return soap->error;
if ((soap->mode & SOAP_IO_LENGTH))
{ if (soap_envelope_begin_out(soap)
|| soap_putheader(soap)
|| soap_body_begin_out(soap)
|| soap_put___wsdd__ProbeMatches(soap, &soap_tmp___wsdd__ProbeMatches, "-wsdd:ProbeMatches", "")
|| soap_body_end_out(soap)
|| soap_envelope_end_out(soap))
return soap->error;
}
if (soap_end_count(soap))
return soap->error;
if (soap_connect(soap, soap_endpoint, soap_action)
|| soap_envelope_begin_out(soap)
|| soap_putheader(soap)
|| soap_body_begin_out(soap)
|| soap_put___wsdd__ProbeMatches(soap, &soap_tmp___wsdd__ProbeMatches, "-wsdd:ProbeMatches", "")
|| soap_body_end_out(soap)
|| soap_envelope_end_out(soap)
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}
SOAP_FMAC5 int SOAP_FMAC6 SOAP_ENV__Fault(struct soap* soap, char *faultcode, char *faultstring, char *faultactor,
struct SOAP_ENV__Detail *detail, struct SOAP_ENV__Code *_SOAP_ENV__Code,
struct SOAP_ENV__Reason *SOAP_ENV__Reason, char *SOAP_ENV__Node,
char *SOAP_ENV__Role, struct SOAP_ENV__Detail *SOAP_ENV__Detail)
{
return 0;
}
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__Hello(struct soap* soap, struct wsdd__HelloType *wsdd__Hello)
{
return 0;
}
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__Bye(struct soap* soap, struct wsdd__ByeType *wsdd__Bye)
{
return 0;
}
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__ProbeMatches(struct soap* soap, struct wsdd__ProbeMatchesType *wsdd__ProbeMatches)
{
return 0;
}
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__Resolve(struct soap* soap, struct wsdd__ResolveType *wsdd__Resolve)
{
return 0;
}
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__ResolveMatches(struct soap* soap, struct wsdd__ResolveMatchesType *wsdd__ResolveMatches)
{
return 0;
}
SOAP_FMAC5 int SOAP_FMAC6 __tdn__Hello(struct soap* soap, struct wsdd__HelloType tdn__Hello, struct wsdd__ResolveType *tdn__HelloResponse)
{
return 0;
}
SOAP_FMAC5 int SOAP_FMAC6 __tdn__Bye(struct soap* soap, struct wsdd__ByeType tdn__Bye, struct wsdd__ResolveType *tdn__ByeResponse)
{
return 0;
}
SOAP_FMAC5 int SOAP_FMAC6 __tdn__Probe(struct soap* soap, struct wsdd__ProbeType tdn__Probe, struct wsdd__ProbeMatchesType *tdn__ProbeResponse)
{
return 0;
}
#define IP "192.168.1.125" //服务器IP
#define ONVIF_TCP_PORT 8554 //服务器访问端口(随意设置)
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__Probe(struct soap* soap, struct wsdd__ProbeType *wsdd__Probe)
{
char scopes_message[] =
"onvif://www.onvif.org/type/NetworkVideoTransmitter\r\n"
"onvif://www.onvif.org/Profile/Streaming\r\n"
"onvif://www.onvif.org/Profile/Q/Operational\r\n"
"onvif://www.onvif.org/hardware/HD1080P\r\n"
"onvif://www.onvif.org/name/discover_test\r\n"
"onvif://www.onvif.org/location/city/GuangZhou\r\n"
"onvif://www.onvif.org/location/country/China\r\n";
// response ProbeMatches
struct wsdd__ProbeMatchesType wsdd__ProbeMatches = {0};
struct wsdd__ProbeMatchType *pProbeMatchType = NULL;
struct wsa__Relationship *pWsa__RelatesTo = NULL;
pProbeMatchType = (struct wsdd__ProbeMatchType*)soap_malloc(soap, sizeof(struct wsdd__ProbeMatchType));
soap_default_wsdd__ProbeMatchType(soap, pProbeMatchType);
char str_tmp[256] = {0};
//sprintf(str_tmp, "http://%s:%d/onvif/device_service", IP, ONVIF_TCP_PORT);
sprintf(str_tmp, "rtsp://%s:%d/live.ts", IP, ONVIF_TCP_PORT);
pProbeMatchType->XAddrs = soap_strdup(soap, str_tmp);
if( wsdd__Probe->Types && strlen(wsdd__Probe->Types) )
pProbeMatchType->Types = soap_strdup(soap, wsdd__Probe->Types);
else
pProbeMatchType->Types = soap_strdup(soap, "dn:NetworkVideoTransmitter tds:Device");
pProbeMatchType->MetadataVersion = 1;
// Build Scopes Message
struct wsdd__ScopesType *pScopes = NULL;
pScopes = (struct wsdd__ScopesType *)soap_malloc(soap, sizeof(struct wsdd__ScopesType));
soap_default_wsdd__ScopesType(soap, pScopes);
pScopes->MatchBy = NULL;
pScopes->__item = soap_strdup(soap, scopes_message);
pProbeMatchType->Scopes = pScopes;
char g_uuid[64];
//snprintf(g_uuid, 64, "%s", soap_wsa_rand_uuid(soap));
//pProbeMatchType->wsa__EndpointReference.Address = soap_strdup(soap, g_uuid);
wsdd__ProbeMatches.__sizeProbeMatch = 1;
wsdd__ProbeMatches.ProbeMatch = pProbeMatchType;
// Build SOAP Header
pWsa__RelatesTo = (struct wsa__Relationship*)soap_malloc(soap, sizeof(struct wsa__Relationship));
soap_default__wsa__RelatesTo(soap, pWsa__RelatesTo);
pWsa__RelatesTo->__item = soap->header->wsa__MessageID;
soap->header->wsa__RelatesTo = pWsa__RelatesTo;
soap->header->wsa__Action = soap_strdup(soap, "http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches");
soap->header->wsa__To = soap_strdup(soap, "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous");
soap_send___wsdd__ProbeMatches(soap, "http://", NULL, &wsdd__ProbeMatches);
return SOAP_OK;
}
int main(int argc,char ** argv)
{
#define ONVIF_LISTEN_PORT 3702
printf("[%s][%d][%s][%s] start \n", __FILE__, __LINE__, __TIME__, __func__);
int count = 0;
struct soap ServerSoap;
struct ip_mreq mcast;
soap_init1(&ServerSoap, SOAP_IO_UDP | SOAP_XML_IGNORENS);
soap_set_namespaces(&ServerSoap, namespaces);
printf("[%s][%d][%s][%s] ServerSoap.version = %d \n", __FILE__, __LINE__, __TIME__, __func__, ServerSoap.version);
if(!soap_valid_socket(soap_bind(&ServerSoap, NULL, ONVIF_LISTEN_PORT, 10)))
{
soap_print_fault(&ServerSoap, stderr);
exit(1);
}
mcast.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
mcast.imr_interface.s_addr = htonl(INADDR_ANY);
if(setsockopt(ServerSoap.master, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast)) < 0)
{
printf("setsockopt error! error code = %d,err string = %s\n",errno,strerror(errno));
return 0;
}
for(;;)
{
if(soap_serve(&ServerSoap))
{
soap_print_fault(&ServerSoap, stderr);
}
soap_destroy(&ServerSoap);
soap_end(&ServerSoap);
//客户端的IP地址
printf("RECEIVE count %d, connection from IP = %lu.%lu.%lu.%lu socket = %d \r\n", count, ((ServerSoap.ip)>>24)&0xFF, ((ServerSoap.ip)>>16)&0xFF, ((ServerSoap.ip)>>8)&0xFF,(ServerSoap.ip)&0xFF, (ServerSoap.socket));
count++;
}
//分离运行时的环境
soap_done(&ServerSoap);
return 0;
}
7、生成Makefile
PWD := $(shell pwd)
CPP=gcc
#CFLAGS=-Wall -g -I../gsoap/plugin/
CFLAGS=-Wall
TARGET1 = $(PWD)/server
all: $(TARGET1)
$(TARGET1):$(OBJ)
$(CPP) $(CFLAGS) -o $@ main.c soapC.c soapServer.c stdsoap2.c wsaapi.c
clean:
rm $(TARGET1)
8、编译运行测试
测试onvif的发现设备的方法: