预备知识

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.htmgSOAP-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
[cpp] view plaincopy
  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 );
[cpp] view plaincopy
  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 );
3、产生代码框架我们执行一下命令,自动生成一些远程调用需要的文件。(先将他们加如到系统环境变量中)soapcpp2 -c add.h
-c是产生纯C代码,如果提示找不到typemap.dat,将gsoap-2.8\gsoap下的typemap.dat复制到当前目录就可以了。通过上列命令我们会得到如下文件:
先大概记住他们的名字,将来会提到他们。4、添加服务端代码,创建文件:addserver.c
[cpp] view plaincopy
  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
[cpp] view plaincopy
  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
5、添加客户端代码,创建文件:addclient.c
[cpp] view plaincopy
  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. }
[cpp] view plaincopy
  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. }
6、写客户端测试代码,创建文件:addtest.c
[cpp] view plaincopy
  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. }
[cpp] view plaincopy
  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. }
7、编写Makefile,编译前,先将gsoap-2.8\gsoap目录下的stdsoap2.c和stdsoap2.h复制到当前目录下,它提供了对SOAP协议的简单调用。
[cpp] view plaincopy
  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
[cpp] view plaincopy
  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
8、编译服务端make server,编译客户端make client 得到addserver和addtest9、测试

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

实例分析

服务端代码下面我们来分析上面的例子,刚才我们只是创建一个add.h头文件,在add.h头文件中声明了一个函数:
[cpp] view plaincopy
  1. int ns2__add( int num1, int num2, int* sum );
[cpp] view plaincopy
  1. 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函数的调用

c/c++使用gsoap发布和调用webservice相关推荐

  1. spring boot整合cxf发布和调用webservice

    一.前言 说起web service最近几年restful大行其道,大有取代传统soap web service的趋势,但是一些特有或相对老旧的系统依然使用了传统的soap web service,例 ...

  2. java中使用axis发布和调用webService

    axis1.4版本编写调用webservice接口 第一步:引入jar包 <!-- axis --><dependency><groupId>org.apache. ...

  3. [PHP]php发布和调用Webservice接口的案例

    分两步走:1.服务端发布接口;2.客户端调用方法 1.服务端发布接口: 需要nusoap工具,下载地址:http://sourceforge.net/projects/nusoap/ 下载完和要发布接 ...

  4. gsoap(C/C++调用webservice)

    C/C++调用Web Service需要用到soap库,一般使用的有gsoap和axis cpp两种实现,这里使用gsoap来调用.gsoap是sourceforge上的一个开源项目,目前版本是2.7 ...

  5. java cxf 不使用springmvc_使用cfx与springMVC集成发布与调用webservice

    客户端调用代码 Client.java package com.quickmap.common; import javax.xml.namespace.QName; import javax.xml. ...

  6. PHP Webservice的发布与调用

    PHP Webservice的发布与调用 1.  环境配置 配置php.ini,把php_soap.dll前面的分号去掉, 不然会报错 class soapserver not found 重启apa ...

  7. Axis2 webservice入门--Webservice的发布与调用

    一.Webservice发布 参考 http://www.cnblogs.com/demingblog/p/3263576.html 二.webservice 调用 部分参考:http://www.c ...

  8. C# WebService发布与调用方法(转)

    Web Service是可操作的分布式应用程序.它以SOAP作为基本通信协议,使用HTTP和XML进行可以穿越防火墙的自由通信. 错误提示: * 出现 访问 IIS 元数据库失败 * iis 无法显示 ...

  9. C++利用gSoap调用WebService服务

    最近要利用C++调用WebService接口,中间工具是gSoap,IDE:VS2010,WebService接口:http://webservice.webxml.com.cn/WebService ...

最新文章

  1. 声音定位研究中遇到的困难
  2. orcle 删除表报正在使用_ORA-14452:试图创建,更改或删除正在使用的临时表中的索引...
  3. [裴礼文数学分析中的典型问题与方法习题参考解答]5.1.27
  4. 博客积分规则 博客等级
  5. Android 渗透测试学习手册 翻译完成!
  6. mediarecoder 安卓_android 通过MediaRecorder实现简单的录音示例
  7. ELK-Metricbeat安装及使用
  8. Eclipse 编辑代码字体的设置
  9. linux 查看gc情况
  10. Meson构建系统(一)
  11. 路由器组成及路由器发展概述
  12. Team Tic Tac Toe 题解
  13. SpringWeb项目Maven执行clean命令后编译拒绝访问的解决方法
  14. 《黑客与画家》摘要读后感
  15. macOS 网络已连接但无法使用的一种情况
  16. 云和恩墨23届校园招聘,内推NTANNzK
  17. 【转】Linux设备驱动之sysfs
  18. 一个公众号绑定多个商户支付
  19. 浏览器输入一个URL地址后发生的事情
  20. 巴别塔合约作战终端开发日记2——Linux系统部署项目

热门文章

  1. linux进入文件夹命令,如何在 Linux 中不使用 CD 命令进入目录/文件夹?
  2. vue引入组件时‘@/xxxx’的意思
  3. opencv的K近邻算法
  4. MFC Combo-box显示大小
  5. 【Tools】怎样转载博客到CSDN博客(很实用)
  6. 【自动驾驶】28.【右手坐标系】与【右手法则】分析、【右手法则的正方向】 与 【逆时针为正方向】 的分析
  7. Linux(Ubuntu14.04)下安装Anaconda和Spyder
  8. Caffe学习系列(12):训练和测试自己的图片
  9. MSRCR(Multi-Scale Retinex with Color Restore)多尺度Retinex图像增强
  10. SpringBoot技术栈搭建个人博客【项目准备】