ONVIF学习【2】——SOAP介绍以及gSOAP使用

预备知识

  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

  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

//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
#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
#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
#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协议的简单调用。
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头文件中声明了一个函数:

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函数的调用
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用gSOAP生成Onvif服务端,你需要按照以下步骤操作: 1. 下载和安装gSOAP:首先,你需要从gSOAP官方网站(https://www.genivia.com/downloads.html)下载并安装gSOAP工具包。根据你的操作系统选择合适的版本,并按照官方文档进行安装步骤。 2. 定义服务接口:使用gSOAP的接口定义语言(IDL)来定义你的Onvif服务接口。在IDL文件中,你可以定义服务的方法、参数和返回类型等。确保按照Onvif规范来定义你的服务接口。 3. 生成代码:使用gSOAP提供的工具来生成C/C++代码。你需要使用命令行工具 `soapcpp2` 并提供IDL文件作为输入。执行命令后,gSOAP将生成相应的服务端和客户端代码文件。 4. 实现服务逻辑:根据生成的代码,你需要实现Onvif服务的具体逻辑。这包括处理接收到的请求、执行相应的操作并构建响应。 5. 编译和构建:编译你的服务端代码,并链接所需的库文件。确保按照gSOAP文档提供的指导进行编译和构建步骤。 6. 运行服务端:运行生成的服务端程序,并确保它能够监听和处理来自客户端的请求。 请注意,这只是一个概述性的步骤,具体的实施可能因个人需求和环境而异。在实际开发中,你还需要了解Onvif协议规范和gSOAP工具的详细用法,并根据实际情况进行适当的配置和定制。 希望这些信息对你有所帮助!如果你有进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值