预备知识

ONVIF规范中设备管理和控制部分所定义的接口均以Web Services的形式提供。ONVIF规范涵盖了完全的XML及WSDL的定义。每一个支持ONVIF规范的终端设备均须提供与功能相应的Web Service。服务端与客户端的数据交互采用SOAP协议。【来自http://blog.csdn.net/ghostyu】

ONVIF中的其他部分比如音视频流则通过RTP/RTSP进行 。

那么WebServices、SOAP、WSDL、gSOAP又都是什么?

假如我们需要开发一个linux上的app,这个app需要与远端的Web服务有一个交互,比如获取一个运算结果、或者是天气等,那么我们就需要使用WebServices。

Web Services可以概述为:

Web Services 可以将应用程序转换为网络应用程序。
通过使用 Web Services,应用程序可以向全世界发布信息,或提供某项功能。
Web Services 可以被其他应用程序使用。
通过 Web Services,会计部门的 Win 服务器可以与 IT 供应商的 UNIX 服务器相连接。
基本的 Web Services 平台是 XML+HTTP。
Web services 使用 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可以产生用于开发Web Services的SOAP通信协议方面的代码框架,开发人员只需要实现server的被调用的函数,然后在client端就可以像调用本地函数一样调用在远端的函数。gSOAP包含两个工具wsdl2h和soapcpp2,用来产生代码框架。

开发Web服务程序,需使用gSOAP生成服务器端和客户端代码框架(通常情况下之需要实现server端或者实现client,因为另一端通常是别人做好的,比如ipnc中的onvif,实现的server端)。我们有两种做法:

编写WSDL,使用wsdl2h生成头文件,再soapcpp2生成框架代码;
编写头文件,使用soapcpp2生成框架代码;
这两种方式,结果是一样的,最终都有产生头文件,并生成代码。不同在于,在项目的开发中需要维护的文件不同,前者是需要维护WSDL文件,后者维护头文件。

SOAP调用示例

下面就使用第二种方法来实现一个简单的通信实例:在远端实现两数相加,然后返回运算结果。

1、下载gSOAP

我使用的版本时2.8.8,http://www.kuaipan.cn/file/id_48923272389088693.htm

gSOAP-2.8软件包不需要安装,直接解压,在gsoap-2.8\gsoap\bin目录下是上面提到的两个命令行工具,包含win32、linux、maxOS等三种版本,在使用soapcpp2生产代码框架时一般需要gsoap-2.8\gsoap\import目录下和gsoap-2.8\gsoap\custom的 文件。在命令行中使用-I<PATH>包含进来即可。

2、编写头文件:add.h

在这里我们不需要wsdl的文件,可以直接从.h文件来生成代码。我们定义一个函数声明文件,用来定义接口函数,名称为add.h

  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 );
//gsoapopt cw
//gsoap ns2 schema namespace: urn:add
//gsoap ns2 schema form: unqualified
//gsoap ns2 service name: add
//gsoap ns2 service type: addPortType
//gsoap ns2 service port:http://websrv.cs.fsu.edu/~engelen/addserver.cgi
//gsoap ns2 service namespace: urn:add
//gsoap ns2 service transport: http://schemas.xmlsoap.org/soap/http
//gsoap ns2 service method-style: add rpc
//gsoap ns2 service method-encoding: add http://schemas.xmlsoap.org/soap/encoding/
//gsoap ns2 service method-action: add ""
int ns2__add( int num1, int num2, int* sum );

3、产生代码框架

我们执行一下命令,自动生成一些远程调用需要的文件。(先将他们加如到系统环境变量中)

soapcpp2 -c add.h

-c是产生纯C代码,如果提示找不到typemap.dat,将gsoap-2.8\gsoap下的typemap.dat复制到当前目录就可以了。通过上列命令我们会得到如下文件:

先大概记住他们的名字,将来会提到他们。

4、添加服务端代码,创建文件:addserver.c

  1. #include "soapH.h"
  2. #include "add.nsmap"
  3. int main(int argc, char **argv)
  4. {
  5. int m, s;
  6. struct soap add_soap;
  7. soap_init(&add_soap);
  8. soap_set_namespaces(&add_soap, namespaces);
  9. if (argc < 2) {
  10. printf("usage: %s <server_port> \n", argv[0]);
  11. exit(1);
  12. } else {
  13. m = soap_bind(&add_soap, NULL, atoi(argv[1]), 100);
  14. if (m < 0) {
  15. soap_print_fault(&add_soap, stderr);
  16. exit(-1);
  17. }
  18. fprintf(stderr, "Socket connection successful: master socket = %d\n", m);
  19. for (;;) {
  20. s = soap_accept(&add_soap);
  21. if (s < 0) {
  22. soap_print_fault(&add_soap, stderr);
  23. exit(-1);
  24. }
  25. fprintf(stderr, "Socket connection successful: slave socket = %d\n", s);
  26. soap_serve(&add_soap);
  27. soap_end(&add_soap);
  28. }
  29. }
  30. return 0;
  31. }
  32. #if 1
  33. int ns2__add(struct soap *add_soap, int num1, int num2, int *sum)
  34. {
  35. *sum = num1 + num2;
  36. return 0;
  37. }
  38. #endif
#include "soapH.h"
#include "add.nsmap" int main(int argc, char **argv)
{
int m, s;
struct soap add_soap;
soap_init(&add_soap);
soap_set_namespaces(&add_soap, namespaces); if (argc < 2) {
printf("usage: %s <server_port> \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, "Socket connection successful: master socket = %d\n", m);
for (;;) {
s = soap_accept(&add_soap);
if (s < 0) {
soap_print_fault(&add_soap, stderr);
exit(-1);
}
fprintf(stderr, "Socket connection successful: slave socket = %d\n", s);
soap_serve(&add_soap);
soap_end(&add_soap);
}
}
return 0;
}
#if 1
int ns2__add(struct soap *add_soap, int num1, int num2, int *sum)
{
*sum = num1 + num2;
return 0;
}
#endif

5、添加客户端代码,创建文件:addclient.c

  1. #include "soapStub.h"
  2. #include "add.nsmap"
  3. int add(const char *server, int num1, int num2, int *sum)
  4. {
  5. struct soap add_soap;
  6. int result = 0;
  7. soap_init(&add_soap);
  8. soap_set_namespaces(&add_soap, namespaces);
  9. soap_call_ns2__add(&add_soap, server, NULL, num1, num2, sum);
  10. printf("server is %s, num1 is %d, num2 is %d/n", server, num1, num2);
  11. if (add_soap.error) {
  12. printf("soap error: %d, %s, %s\n", add_soap.error, *soap_faultcode(&add_soap), *soap_faultstring(&add_soap));
  13. result = add_soap.error;
  14. }
  15. soap_end(&add_soap);
  16. soap_done(&add_soap);
  17. return result;
  18. }
#include "soapStub.h"
#include "add.nsmap" int add(const char *server, int num1, int num2, int *sum)
{
struct soap add_soap;
int result = 0;
soap_init(&add_soap);
soap_set_namespaces(&add_soap, namespaces);
soap_call_ns2__add(&add_soap, server, NULL, num1, num2, sum);
printf("server is %s, num1 is %d, num2 is %d/n", server, num1, num2); if (add_soap.error) {
printf("soap error: %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);
return result;
}

6、写客户端测试代码,创建文件:addtest.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. int add(const char *server, int num1, int num2, int *sum);
  5. int main(int argc, char **argv)
  6. {
  7. int result = -1;
  8. char server[128] = {0};
  9. int num1;
  10. int num2;
  11. int sum;
  12. if (argc < 4) {
  13. printf("usage: %s <ip:port> num1 num2 \n", argv[0]);
  14. exit(1);
  15. }
  16. strcpy(server,argv[1]);
  17. num1 = atoi(argv[2]);
  18. num2 = atoi(argv[3]);
  19. result = add(server, num1, num2,&sum);
  20. if (result != 0) {
  21. printf("soap error, errcode=%d\n", result);
  22. } else {
  23. printf("%d + %d = %d\n", num1, num2, sum);
  24. }
  25. return 0;
  26. }
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int add(const char *server, int num1, int num2, int *sum);
int main(int argc, char **argv)
{
int result = -1;
char server[128] = {0};
int num1;
int num2;
int sum; if (argc < 4) {
printf("usage: %s <ip:port> num1 num2 \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("soap error, errcode=%d\n", result);
} else {
printf("%d + %d = %d\n", num1, num2, sum);
}
return 0;
}

7、编写Makefile,编译前,先将gsoap-2.8\gsoap目录下的stdsoap2.c和stdsoap2.h复制到当前目录下,它提供了对SOAP协议的简单调用。

  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. all: server
  7. server: $(SERVER_OBJS)
  8. $(CC) $(INCLUDE) -o addserver $(SERVER_OBJS)
  9. client: $(CLIENT_OBJS)
  10. $(CC) $(INCLUDE) -o addtest $(CLIENT_OBJS)
  11. clean:
  12. rm -f *.o addtest
GSOAP_ROOT = /root/onvif/gsoap-2.8/gsoap
CC = gcc -g -DWITH_NONAMESPACES
INCLUDE = -I$(GSOAP_ROOT)
SERVER_OBJS = soapC.o stdsoap2.o soapServer.o addserver.o
CLIENT_OBJS = soapC.o stdsoap2.o soapClient.o addclient.o addtest.o all: server
server: $(SERVER_OBJS)
$(CC) $(INCLUDE) -o addserver $(SERVER_OBJS) client: $(CLIENT_OBJS)
$(CC) $(INCLUDE) -o addtest $(CLIENT_OBJS) clean:
rm -f *.o addtest

8、编译服务端make server,编译客户端make client 得到addserver和addtest

9、测试

一个最简单的soap调用的例子完成了。

实例分析

服务端代码

下面我们来分析上面的例子,刚才我们只是创建一个add.h头文件,在add.h头文件中声明了一个函数:

  1. int ns2__add( int num1, int num2, int* sum );
int ns2__add( int num1, int num2, int* sum );

其他所有的的代码都是一句他来生成的。那么这个的实体在哪?对,就是在需要我们自己添加的addserver.c中:


但是它好像多了一个struct soap类型的参数,这是soap全局运行环境,所有的函数都第一个包含这个参数。注意上面的Makefile,不管是编译server还是编译client都是没有用到刚才的add.h文件的。ns2__add真正的声明在自动产生的soapStub.h中

然后在自动产生的soapServer.c中被soap_serve_ns2__add()函数调用。这样,就将真正的加法运算的ns2__add函数和soap代码框架联系了起来。那么,在客户端的代码中又是怎样来调用这个远程函数的呢?

客户端代码

在刚才添加的addtest.c中main函数中调用一个简单的add函数

这个函数的实现也是我们自己添加的,在addclient.c中:

这个函数有些复杂,因为它把客户端的调用和soap联系了起来,还记得吗,我们编译server和client的时候复制了两个文件stdsoap2.h和stdsoap2.c,这里面的soap_init() soap_end()等函数来自他们。stdsoap2提供了soap协议的简单操作,之需要简单的函数调用就能完成远程的函数调用。注意soap_call_ns2__add(),它同样在soapStub.h中声明,只不过是Client-Side Call Stubs,不明白stub意思的可以搜索rpc

这个函数的实现在自动产生的soapClient.c源文件中。同样不需要我们实现。

这样就可以通过调用gSOAP提供的stdsoap2的soap_init和自动产生的soap_call_ns2__add就实现了远程主机上的ns2__add函数的调用

onvif规范的实现:使用gSOAP创建SOAP调用实例的更多相关文章

  1. onvif规范的实现:成功实现ONVIF协议RTSP-Video-Stream与OnvifDeviceManager的视频对接

    有了前几篇的基础,现在可以正式开始onvif的实现工作,其中一项非常重要的部分就是视频流的对接,即能够在符合onvif标准的监控客户端软件里接收到设备端NVT发来的RTSP视频流.这里,我所用的客户端 ...

  2. onvif规范 中文介绍

    什么是ONVIF ? ONVIF规范描述了网络视频的模型.接口.数据类型以及数据交互的模式.并复用了一些现有的标准,如WS系列标准等. ONVIF规范的目标是实现一个网络视频框架协议,使不同厂商所生产 ...

  3. gsoap创建webservice服务简单教程

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] WebServicesoapgsoap 使用gsoap创建webservice服务 下载gsop 准备待导出的服务接口定义文件比 ...

  4. VS2010使用c++、gSOAP创建WebService 图文教程

    VS2010使用c++.gSOAP创建的WebService 图文教程 环境 操作系统:Windows 7gsoap版本:2.8.32C++编译器/开发环境:Visual Studio 2010 gS ...

  5. 如何在symfony 控制器里面创建soap web service

    通过一些工具将一个控制器设置成一个soap服务将会非常简单.首先,你必须安装了php soap扩展.由于php soap扩展现在不能生成wsdl,你要么自己从头开始创建要模使用第三方生成器. php中 ...

  6. C#创建和调用WebService详细教程

    1.1.Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求, ...

  7. php中创建和调用webservice接口示例

    php中创建和调用webservice接口示例   这篇文章主要介绍了php中创建和调用webservice接口示例,包括webservice基本知识.webservice服务端例子.webservi ...

  8. PHP5下SOAP调用实现过程

    本文以某公司iPhone 6手机预约接口开发为例,介绍PHP5下SOAP调用的实现过程. 一.基础概念 SOAP(Simple Object Access Protocol )简单对象访问协议是在分散 ...

  9. PHP使用SOAP调用.net的WebService数据

    需要和一个.net系统进行数据交换,对方提供了一个WebService接口,使用PHP如何调用这个数据呢,下面就看看使用SOAP调用的方法吧 这个与一般的PHP POST或GET传值再查库拿数据的思路 ...

随机推荐

  1. Code Complete阅读笔记(一)

    代码大全也读了好几个月了,一开始读中文版,到现在慢慢尝试着读原版,确实感受到了"每天进步一点点"的魅力.遗憾的是没有从一开始就做阅读记录,总有不能尽兴和思路不清之感.确实,就像项目 ...

  2. Ext.net GridPanel获取选中行的数据

    1.前台页面 在button中添加ExtraParams   <DirectEvents> <Click> <ExtraParams> <ext:Pramet ...

  3. CString常用操作

    ①.CString 类对象的初始化: CString str; CString str1(_T("abc")); CString str2 = _T("defg" ...

  4. UVALive 4119 Always an integer (差分数列,模拟)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Always an integer Time Limit:3000MS     M ...

  5. (原)Eclipse的java中文件读写

    1 在<uses-sdk…/>下面添加permission <uses-sdk android:minSdkVersion="16" android:target ...

  6. centos 6.4从源码安装mysql 5.6笔记

    上周在安装mysql时遇到了些许麻烦,今天整理下. 在代码目录建立obj文件夹. 在obj目录下,执行cmake .. -DXXX  // XXX表示一些参数,详见http://dev.mysql.c ...

  7. Java中的各种o

    java的po vo dao dto pojo 1各个术语的简介 PO(persistant object)持久对象 最形象的理解就是一个PO就是数据库中的一条记录.PO是在ORM中出现的概念,就是O ...

  8. 我的开源框架之Accordion控件

    需求: (1)实现手风琴面板控件,支持静态HTML与JSON方式创建控件 (2)支持远程加载数据 (3)支持面板激活.远程加载事件注册 (4)支持动态添加.删除项目 实现图例 客户代码 <div ...

  9. laravel 心得

    1.安装 使用composer安装laravel ,切换到你想要放置该网站的目录下,运行命令: composer create-project laravel/larevel project 4.1 ...

  10. CI(CodeIgniter)学习第二讲

    一.CI的文件结构: 了解CI的文件结构可以帮助我们快速的对CI框架有一个整体的认识,就好像我们去了一个陌生的城市一样,对你来讲周围的一切都是陌生和未知的,要想快速的了解这座城市,你可以买一张这座城市 ...