0002onvif规范的实现使用gSOAP创建SOAP调用实例.docx
《0002onvif规范的实现使用gSOAP创建SOAP调用实例.docx》由会员分享,可在线阅读,更多相关《0002onvif规范的实现使用gSOAP创建SOAP调用实例.docx(13页珍藏版)》请在冰豆网上搜索。
0002onvif规范的实现使用gSOAP创建SOAP调用实例
预备知识
ONVIF规范中设备管理和控制部分所定义的接口均以WebServices的形式提供。
ONVIF规范涵盖了完全的XML及WSDL的定义。
每一个支持ONVIF规范的终端设备均须提供与功能相应的WebService。
服务端与客户端的数据交互采用SOAP协议。
【来自
ONVIF中的其他部分比如音视频流则通过RTP/RTSP进行。
那么WebServices、SOAP、WSDL、gSOAP又都是什么?
假如我们需要开发一个linux上的app,这个app需要与远端的Web服务有一个交互,比如获取一个运算结果、或者是天气等,那么我们就需要使用WebServices。
WebServices可以概述为:
WebServices可以将应用程序转换为网络应用程序。
通过使用WebServices,应用程序可以向全世界发布信息,或提供某项功能。
WebServices可以被其他应用程序使用。
通过WebServices,会计部门的Win服务器可以与IT供应商的UNIX服务器相连接。
基本的WebServices平台是XML+HTTP。
Webservices使用XML来编解码数据,并使用SOAP来传输数据。
SOAP又是什么?
SOAP是基于XML的简易协议,可使应用程序在HTTP之上进行信息交换。
或者更简单地说:
SOAP是用于访问网络服务的协议。
对于应用程序开发来说,使程序之间进行因特网通信是很重要的。
目前的应用程序通过使用远程过程调用(RPC)在诸如DCOM与CORBA等对象之间进行通信,但是HTTP不是为此设计的。
RPC会产生兼容性以及安全问题;防火墙和代理服务器通常会阻止此类流量。
通过HTTP在应用程序间通信是更好的方法,因为HTTP得到了所有的因特网浏览器及服务器的支持。
SOAP就是被创造出来完成这个任务的。
SOAP提供了一种标准的方法,使得运行在不同的操作系统并使用不同的技术和编程语言的应用程序可以互相进行通信。
如何实现SOAP?
我们要知道SOAP协议是基于XML的,那么如何能够将他们嵌入到C/C++的应用程序里使用?
gSOAP编译工具就提供了一个SOAP/XML关于C/C++语言的实现,从而让C/C++语言开发web服务或客户端程序的工作变得轻松了很多。
将与开发无关的SOAP协议的实现细节相关的内容对开发人员隐藏起来。
因为SOAP提供的是一种标准化的方法,gSOAP的编译器能够自动的将用户定义的本地化的C或C++数据类型转变为符合XML语法的数据结构,这样,只用一组简单的API就将用户从SOAP细节实现工作中解脱了出来,可以专注与应用程序逻辑的实现工作了。
并且可以跨越多个操作系统、语言环境以及在防火墙后的不同组织。
更直白的说,使用gSOAP可以产生用于开发WebServices的SOAP通信协议方面的代码框架,开发人员只需要实现server的被调用的函数,然后在client端就可以像调用本地函数一样调用在远端的函数。
gSOAP包含两个工具wsdl2h和soapcpp2,用来产生代码框架。
开发Web服务程序,需使用gSOAP生成服务器端和客户端代码框架(通常情况下之需要实现server端或者实现client,因为另一端通常是别人做好的,比如ipnc中的onvif,实现的server端)。
我们有两种做法:
编写WSDL,使用wsdl2h生成头文件,再soapcpp2生成框架代码;
编写头文件,使用soapcpp2生成框架代码;
这两种方式,结果是一样的,最终都有产生头文件,并生成代码。
不同在于,在项目的开发中需要维护的文件不同,前者是需要维护WSDL文件,后者维护头文件。
SOAP调用示例
下面就使用第二种方法来实现一个简单的通信实例:
在远端实现两数相加,然后返回运算结果。
1、下载gSOAP
我使用的版本时2.8.8,
gSOAP-2.8软件包不需要安装,直接解压,在gsoap-2.8\gsoap\bin目录下是上面提到的两个命令行工具,包含win32、linux、maxOS等三种版本,在使用soapcpp2生产代码框架时一般需要gsoap-2.8\gsoap\import目录下和gsoap-2.8\gsoap\custom的文件。
在命令行中使用-I包含进来即可。
2、编写头文件:
add.h
在这里我们不需要wsdl的文件,可以直接从.h文件来生成代码。
我们定义一个函数声明文件,用来定义接口函数,名称为add.h
[cpp]viewplaincopyprint?
1.//gsoapopt cw
2.//gsoap ns2 schema namespace:
urn:
add
3.//gsoap ns2 schema form:
unqualified
4.//gsoap ns2 service name:
add
5.//gsoap ns2 service type:
addPortType
6.//gsoap ns2 service port:
http:
//websrv.cs.fsu.edu/~engelen/addserver.cgi
7.//gsoap ns2 service namespace:
urn:
add
8.//gsoap ns2 service transport:
http:
//schemas.xmlsoap.org/soap/http
9.//gsoap ns2 service method-style:
add rpc
10.//gsoap ns2 service method-encoding:
add http:
//schemas.xmlsoap.org/soap/encoding/
11.//gsoap ns2 service method-action:
add ""
12.int ns2__add( int num1, int num2, int* sum );
//gsoapoptcw
//gsoapns2schemanamespace:
urn:
add
//gsoapns2schemaform:
unqualified
//gsoapns2servicename:
add
//gsoapns2servicetype:
addPortType
//gsoapns2serviceport:
http:
//websrv.cs.fsu.edu/~engelen/addserver.cgi
//gsoapns2servicenamespace:
urn:
add
//gsoapns2servicetransport:
http:
//schemas.xmlsoap.org/soap/http
//gsoapns2servicemethod-style:
addrpc
//gsoapns2servicemethod-encoding:
addhttp:
//schemas.xmlsoap.org/soap/encoding/
//gsoapns2servicemethod-action:
add""
intns2__add(intnum1,intnum2,int*sum);
3、产生代码框架
我们执行一下命令,自动生成一些远程调用需要的文件。
(先将他们加如到系统环境变量中)
soapcpp2-cadd.h
-c是产生纯C代码,如果提示找不到typemap.dat,将gsoap-2.8\gsoap下的typemap.dat复制到当前目录就可以了。
通过上列命令我们会得到如下文件:
先大概记住他们的名字,将来会提到他们。
4、添加服务端代码,创建文件:
addserver.c
[cpp]viewplaincopyprint?
1.#include "soapH.h"
2.#include "add.nsmap"
3.
4.int main(int argc, char **argv)
5.{
6. int m, s;
7. struct soap add_soap;
8. soap_init(&add_soap);
9. soap_set_namespaces(&add_soap, namespaces);
10.
11. if (argc < 2) {
12. printf("usage:
%s \n", argv[0]);
13. exit
(1);
14. } else {
15. m = soap_bind(&add_soap, NULL, atoi(argv[1]), 100);
16. if (m < 0) {
17. soap_print_fault(&add_soap, stderr);
18. exit(-1);
19. }
20. fprintf(stderr, "Socket connection successful:
master socket = %d\n", m);
21. for (;;) {
22. s = soap_accept(&add_soap);
23. if (s < 0) {
24. soap_print_fault(&add_soap, stderr);
25. exit(-1);
26. }
27. fprintf(stderr, "Socket connection successful:
slave socket = %d\n", s);
28. soap_serve(&add_soap);
29. soap_end(&add_soap);
30. }
31. }
32. return 0;
33.}
34.#if 1
35.int ns2__add(struct soap *add_soap, int num1, int num2, int *sum)
36.{
37. *sum = num1 + num2;
38. return 0;
39.}
40.#endif
#include"soapH.h"
#include"add.nsmap"
intmain(intargc,char**argv)
{
intm,s;
structsoapadd_soap;
soap_init(&add_soap);
soap_set_namespaces(&add_soap,namespaces);
if(argc<2){
printf("usage:
%s\n",argv[0]);
exit
(1);
}else{
m=soap_bind(&add_soap,NULL,atoi(argv[1]),100);
if(m<0){
soap_print_fault(&add_soap,stderr);
exit(-1);
}
fprintf(stderr,"Socketconnectionsuccessful:
mastersocket=%d\n",m);
for(;;){
s=soap_accept(&add_soap);
if(s<0){
soap_print_fault(&add_soap,stderr);
exit(-1);
}
fprintf(stderr,"Socketconnectionsuccessful:
slavesocket=%d\n",s);
soap_serve(&add_soap);
soap_end(&add_soap);
}
}
return0;
}
#if1
intns2__add(structsoap*add_soap,intnum1,intnum2,int*sum)
{
*sum=num1+num2;
return0;
}
#endif
5、添加客户端代码,创建文件:
addclient.c
[cpp]viewplaincopyprint?
1.#include "soapStub.h"
2.#include "add.nsmap"
3.
4.int add(const char *server, int num1, int num2, int *sum)
5.{
6. struct soap add_soap;
7. int result = 0;
8. soap_init(&add_soap);
9. soap_set_namespaces(&add_soap, namespaces);
10. soap_call_ns2__add(&add_soap, server, NULL, num1, num2, sum);
11. printf("server is %s, num1 is %d, num2 is %d/n", server, num1, num2);
12.
13. if (add_soap.error) {
14. printf("soap error:
%d, %s, %s\n", add_soap.error, *soap_faultcode(&add_soap), *soap_faultstring(&add_soap));
15. result = add_soap.error;
16. }
17. soap_end(&add_soap);
18. soap_done(&add_soap);
19. return result;
20.}
#include"soapStub.h"
#include"add.nsmap"
intadd(constchar*server,intnum1,intnum2,int*sum)
{
structsoapadd_soap;
intresult=0;
soap_init(&add_soap);
soap_set_namespaces(&add_soap,namespaces);
soap_call_ns2__add(&add_soap,server,NULL,num1,num2,sum);
printf("serveris%s,num1is%d,num2is%d/n",server,num1,num2);
if(add_soap.error){
printf("soaperror:
%d,%s,%s\n",add_soap.error,*soap_faultcode(&add_soap),*soap_faultstring(&add_soap));
result=add_soap.error;
}
soap_end(&add_soap);
soap_done(&add_soap);
returnresult;
}
6、写客户端测试代码,创建文件:
addtest.c
[cpp]viewplaincopyprint?
1.#include
2.#include
3.#include
4.
5.int add(const char *server, int num1, int num2, int *sum);
6.int main(int argc, char **argv)
7.{
8. int result = -1;
9. char server[128] = {0};
10. int num1;
11. int num2;
12. int sum;
13.
14. if (argc < 4) {
15. printf("usage:
%s port> num1 num2 \n", argv[0]);
16. exit
(1);
17. }
18.
19. strcpy(server,argv[1]);
20. num1 = atoi(argv[2]);
21. num2 = atoi(argv[3]);
22. result = add(server, num1, num2,&sum);
23.
24. if (result !
= 0) {
25. printf("soap error, errcode=%d\n", result);
26. } else {
27. printf("%d + %d = %d\n", num1, num2, sum);
28. }
29. return 0;
30.}
#include
#include
#include
intadd(constchar*server,intnum1,intnum2,int*sum);
intmain(intargc,char**argv)
{
intresult=-1;
charserver[128]={0};
intnum1;
intnum2;
intsum;
if(argc<4){
printf("usage:
%sport>num1num2\n",argv[0]);
exit
(1);
}
strcpy(server,argv[1]);
num1=atoi(argv[2]);
num2=atoi(argv[3]);
result=add(server,num1,num2,&sum);
if(result!
=0){
printf("soaperror,errcode=%d\n",result);
}else{
printf("%d+%d=%d\n",num1,num2,sum);
}
return0;
}
7、编写Makefile,编译前,先将gsoap-2.8\gsoap目录下的stdsoap2.c和stdsoap2.h复制到当前目录下,它提供了对SOAP协议的简单调用。
[cpp]viewplaincopyprint?
1.GSOAP_ROOT = /root/onvif/gsoap-2.8/gsoap
2.CC = gcc -g -DWITH_NONAMESPACES
3.INCLUDE = -I$(GSOAP_ROOT)
4.SERVER_OBJS = soapC.o stdsoap2.o soapServer.o addserver.o
5.CLIENT_OBJS = soapC.o stdsoap2.o soapClient.o addclient.o addtest.o
6.
7.all:
server
8.server:
$(SERVER_OBJS)
9. $(CC) $(INCLUDE) -o addserver $(SERVER_OBJS)
10.
11.client:
$(CLIENT_OBJS)
12. $(CC) $(INCLUDE) -o addtest $(CLIENT_OBJS)
13.
14.clean:
15. rm -f *.o addtest
GSOAP_ROOT=/root/onvif/gsoap-2.8/gsoap
CC=gcc-g-DWITH_NONAMESPACES
INCLUDE=-I$(GSOAP_ROOT)
SERVER_OBJS=soapC.ostdsoap2.osoapServer.oaddserver.o
CLIENT_OBJS=soapC.ostdsoap2.osoapClient.oaddclient.oaddtest.o
all:
server
server:
$(SERVER_OBJS)
$(CC)$(INCLUDE)-oaddserver$(SERVER_OBJS)
client:
$(CLIENT_OBJS)
$(CC)$(INCLUDE)-oaddtest$(CLIENT_OBJS)
clean:
rm-f*.oaddtest
8、编译服务端makeserver,编译客户端makeclient得到addserver和addtest
9、测试
一个最简单的soap调用的例子完成了。
实例分析
服务端代码
下面我们来分析上面的例子,刚才我们只是创建一个add.h头文件,在add.h头文件中声明了一个函数:
[cpp]viewplaincopyprint?
1.int ns2__add( int num1, int num2, int* sum );
intns2__add(intnum1,intnum2,int*sum);
其他所有的的代码都是一句他来生成的。
那么这个的实体在哪?
对,就是在需要我们自己添加的addserver.c中:
但是它好像多了一个structsoap类型的参数,这是soap全局运行环境,所有的函数都第一个包含这个参数。
注意上面的Makefile,不管是编译serve