Gsoap使用精华总结

Gsoap使用总结

一、相关知识简介

关于soap:

1、SOAP 是基于 XML 的简易协议,可使应用程序在 HTTP 之上进行信息交换。或者更简单地说:SOAP 是用于访问网络服务的协议。

2、SOAP 提供了一种标准的方法,使得运行在不同的操作系统并使用不同的技术和编程语言的应用程序可以互相进行通信。

3、关于Soap,它是一种简单对象访问协议,是一种轻量的、简单的、基于 XML 的协议,它被设计成在 WEB 上交换结构化的和固化的信息。它是一种通信协议,用于Web应用程序之间的因特网通信,它提供一组不受平台和语言限制的方法使应用程序得以相互之间进行Intertnet通信。gSoap可以看做是对soap的一个实现封装,它隐藏了在调用WebService中的大量实现细节,使得C++调用WebService变得较为简单。

关于WSDL:

1、WSDL,最初弄的WSDL的时候被这个WSDL弄的焦头烂额的。这个文件实际上就是WebService的对外接口文件,它是一个XML文件,描述了WebService接口的外部方法和抽象方法,以及各协议下的相关调用,是一个用来描述Web服务说明如何与Web服务通信XML语言,为用户提供详细的接口说明书。对于WSDL文件,只需要在浏览器中打开,即可查看到WebService接口的外部供调用的方法。

关于gsoap:

1gSOAP是一个开发SOAPXML应用(它们组成了webservice)的工具,在英文中叫toolkit。它是跨平台的,webservice的客户端和服务器端,都可以用它来辅助开发。

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

3在编写客户端之前我们必须提供webservice的服务器端

 

相关链接

SOAP扫盲  http://www.runoob.com/soap/soap-tutorial.html

gSOAP 2.8.34 User Guide:http://www.cs.fsu.edu/~engelen/soapdoc2.html

gsoap主页http://www.cs.fsu.edu/~engelen/soap.html

gsoap官网 http://gsoap2.sourceforge.net/  到问题时,官网往往是最能提供帮助的地方。

下载地址:http://sourceforge.net/projects/gsoap2

二、gSoap使用入门之自定义接口头文件

示例: cal.h文件

//gsoap ns service name: itoa

//gsoap ns service protocol: SOAP

//gsoap ns service style: rpc

//gsoap ns service namespace: http://localhost:8087/itoa?wsdl

//gsoap ns service location: http://localhost:8087

//gsoap ns service encoding: encoded  

//gsoap ns schema namespace: urn:itoa

 

int ns__itoa(int i, char **a);

int ns__add(double a, double b, double& result);

 

1、service location 如果在客户端调用接口方法时,没有输入服务端地址,方法执行时将自动调用此处的地址做为服务器地址。

2、 gSoap对“_”和“__”(下划线、双下划线)有特殊用法,接口定义时函数名前要加上命名空间名和双下划线
       举例:加法运算    int add(int num1, int num2, int &num3);
      在接口头文件定义时要写成如下格式   int ns__add(int num1, int nmu2, int &num3); 

注意事项:

1>"ns"是命名空间名称,此名称可以自定义成其它名字 但其后"urn:itoa"不可随意更改,这个是要与服务端统一的
 2>"__"是编译时识别符号,如果没有的话xml文件是编译不出来的。
3> "_"(单下划线)定义名称中要慎用,自己定义的变量或函数名称中使用下划线的地方要在下划线后加上"USCORE"
        例 定义 ns__add_sum(int num_1, int num2, int &num_3);
        要写成如下形式:ns__add_USCOREsum(int num_USCORE1, int num2, int &num_USCORE3);

4>"add"是接口函数名 这个是客户端与服务器统一的接口名字。

5> 函数参数变量类型变量名 为客户端与服务器统一的接口。
6>  函数中只有最后一个参数是输出参数,前面的都是输入参数。
7>  多个参数传出(传回),在接口中必须使用结构体
typedef char * xsd__string;
typedef long xsd__int;
struct ns__personResponse
{

xsd__int age;
xsd__string name;
xsd__string address;

};

int ns__person( xsd__string buf_in, struct ns__personResponse * buf_out );

8>   若没有输入参数 可将输入参数类型定义为void (将忽略void 类型的参数)。

9> 函数返回类型必须为 int,可以通过返回值判断接口函数执行情况。注意:这里的int并不是接口的返回值,而是gsoap内部的返回值。真正的返回值是result

 

三、GSOAP工具使用:

1wsdl2h的用法

该工具是可以根据输入的wsdlXSDURL,产生相应的C/C++形式的.h头文件soapcpp2使用。也就是从网络(本地)获取.wsdl文件生成头文件soapcpp2根据生成的头文件生成代码框架

用法:wsdl2h [参数] 头文件名 WSDL文件名或URL(资源地址)

参数:

选项

描述

-a

对匿名类型,产生基于顺序号的结构体名称

-c

生成C代码

-f

schema扩展,产生flat C++

-g

产生全局的元素声明

-h

显示帮助信息

-I path

包含文件时指明路径,相当于#import

-j

不产生 SOAP_ENV__Header SOAP_ENV__Detail 定义

-k

不产生 SOAP_ENV__Header mustUnderstand qualifiers

-l

在输出中包含license信息

-m

 xsd.h 模块来引入类型信息

-N name

name 来指定服务命名空间的前缀。

-n name

name 作为命名空间的前缀,取代缺省的ns

-o file

输出文件名

-q name

所有的声明采用 name 作命名空间

-s

不产生 STL代码 (即不用 std::stringstd::vector)

-t file

使用自己指定的type map file而不是缺省的typemap.dat

-u

不生成 unions

-v

产生详细的输出信息

-w

always wrap response parameters in a response struct

-y

structsenums产生 typedef定义

-_

不产生 _USCORE (UNICODE _x005f代替)

-?

显示帮助信息

-t

指定typemap文件,默认为typemap.dat

-e

禁止为enum成员加上名空间前缀

 

2soapcpp2的用法

根据头文件生成特定的代码框架soapcpp2.exe可以带参数执行,具体执行soapcpp2.exe -h查看。

参数

选项

描述

-1

Soap1.1绑定

-2

SOAP1.2绑定

-C

只生成客户端代码

-S

只生成服务器端代码

-T

生成自动测试代码

-L

不生成 soapClientLib/soapServerLib

-a

 SOAPAction WS-Addressing调用服务器端方法

-A

 SOAPAction 调用服务器端方法

-b

采用char[N]这样的方式来表示string

-c

生成的是C代码,不是C++代码

-d < path >

将代码生成在 < path >

-e

生成 SOAP RPC 样式的绑定

-f N

File split of N XML serializer implementations per file

-h

显示一个简要的用法信息

-i

生成的服务代理Proxy类和对象 struct soap继承而来

-j

生成的服务代理类和对象包含struct soap而来(C代码的唯一选择)

-I < path >

包含其他文件时使用,指明 < path > (多个的话,用`:'分割),相当于#import ,该路径一般是gSOAP目录下的import目录,该目录下有一堆文件供soapcpp2生成代码时使用。

-n

用于生成支持多个客户端和服务器端(具体内容参考gSOAP文档)

-p < name >

生成的文件前缀采用< name > ,而不是缺省的 "soap"

-q < name >

C++代码中,所有声明的命名空间

-s

生成的代码在反序列化时,严格检查XML的有效性

-t

生成的代码在发送消息时,采用xsi:type方式

-u

 WSDL/schema 输出文件中不产生XML注释

-v

显示版本信息

-w

不生成 WSDL  schema 文件

-x

不生成 XML 形式的传输消息文件

-y

XML 形式的传输消息文件中,包含 C/C++类型信息

 

 

3用soapcpp2.exe工具生成文件结构

文件

描述

soapStub.h

根据输入的.h文件生成的数据定义文件,一般我们不直接引用它。

soapH.h

soapC.cpp

客户端服务器端应包含该头文件,它包含了soapStub.h。针对soapStub.h中的数据类型,cpp文件实现了序列化、反序列化方法。

soapXYZProxy.h

soapXYZProxy.cpp

这两个文件用于客户端,是客户端调用webservice的框架文件,我们的代码主要在此实现或从它继承。

soapXYZService.h

soapXYZService.cpp

这两个文件用于服务器端,是服务器端实现webservice的框架文件,我们的代码主要在此实现或从它继承。

.xsd

传输消息的schema,,我们可以看看是否满足我们的协议格式(如果有此要求)

.wsdl

接口定义文件

.xml

满足webservice定义的例子message,即实际的传输消息,我们可以看看是否满足我们的协议格式(如果有此要求)。

.nsmap

命名空间的定义(需添加到服务端与客户端代码中)

soapClient.cpp

客户端代码框架,好像客户端也没有用到该文件。

soapClientLib.cpp

客户端代码框架(一般不使用)

soapServerLib.cpp

服务端代码框架(一般不使用)

 

四、Web server开发:

开发两种方式:

API接口固定,不关心底层的通讯,将SOAP作为应用层协议

当我们拥有头文件(或者自己编写头文件时候,常见用于服务端)

通讯协议固定(当然需要基于XML的)或只有wsdl,将SOAP作为传输层协议

我们能够获取到wsdl文件时候(常见用于客户端)

中文支持:

gsoap传输中文

1.  设置gsoaputf-8传输数据(我使用utf-8编码格式来支持汉字的传输。)
soap_set_mode( &SmsWBS_soap, SOAP_C_UTFSTRING ); //设置编码
SmsWBS_soap.mode|=SOAP_C_UTFSTRING;
2. 使用下面函数转换我们的传输内容,即将我们的数据转成UTF-8编码:
int conv_charset( const char *dest, const char *src, char *input, size_t ilen,char *output, size_t olen )
{
int convlen = olen;
iconv_t conv = iconv_open( dest, src );
if( conv == (iconv_t) -1 )
return -1;
memset( output, 0, olen );
if( iconv( conv, &input, &ilen, &output, &olen ) )

{
iconv_close(conv);
return -1;
}

iconv_close(conv);
return convlen-olen;
}
例子conv_charset( "UTF-8", "GBK", "微软.linxr", strlen("微软.linxr"), buf_out->name,100 );

//编码转换函数

int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen)
{
iconv_t cd;
int rc;
char **pin = &inbuf;
char **pout = &outbuf;

cd = iconv_open(to_charset,from_charset);
if (cd==0) return -1;
memset(outbuf,0,outlen);
if (iconv(cd,pin,&inlen,pout,&outlen)==-1) return -1;
iconv_close(cd);
return 0;
}
//UNICODE 2 GB2312
int u2g(char *inbuf,int inlen,char *outbuf,int outlen)
{
return code_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);
}
//GB2312 2 UNICODE 
int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen)
{
return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}

初始化:

Function

Description

soap_init(struct soap *soap)

初始化运行的环境

soap_init1(struct soap *soap, soap_mode iomode)

初始化运行的环境并设置模式

soap_init2(struct soap *soap, soap_mode imode, soap_mode omode)

初始化运行的环境并设置模式

struct soap *soap_new()

返回一个初始化过的soap指针

struct soap *soap_new1(soap_mode iomode)

返回一个初始化并设置模式后的soap指针

struct soap *soap_new2(soap_mode imode, soap_mode omode)

返回一个初始化并设置模式后的soap指针

struct soap *soap_copy(struct soap *soap)

拷贝一个soap

 

内存释放:

Function

Description

soap_destroy(struct soap *soap)

释放所有动态分配的C++类,必须在soap_end()之前调用。

soap_end(struct soap *soap)

释放所有存储临时数据和反序列化数据中除类之外的空间(soap_malloc的数据也属于反序列化数据)。

soap_done(struct soap *soap)

Detach soap结构(即初始化化soap结构)

soap_free(struct soap *soap)

Detach 且释放soap结构

 

例如:

#include"soapH.h" // include all interfaces (library and generated) 
#include"calc.nsmap" // import the generated namespace mapping table 
int main() 

   double sum; 

//初始化
   struct soap soap; // the gSOAP runtime context 
   soap_init(&soap); // initialize the context (only once!) 

//方法调用
   if (soap_call_c__add(&soap, NULL, NULL, 1.0, 2.0, &sum) == SOAP_OK) 
      std::cout << "Sum = " << sum << std::endl; 
   else // an error occurred 
 soap_print_fault(&soap, stderr); // display the SOAP fault message on the stderr stream 

//释放资源
   soap_destroy(&soap); // delete deserialized class instances (for C++) 
   soap_end(&soap); // remove deserialized data and clean up 
   soap_done(&soap); // detach the gSOAP context 
   return 0; 
}

webserver发布

要能被其他人引用别人需要获得我们的wsdl文件获取到webServer后就会获取到我们的webServer方法

假定我们定义:struct soap Server;

其实就是实现: Server.fget 的函数指针

int  http_get(struct  soap   *soap)

{

FILE*fd = NULL;

char *s = strchr( soap->path, '?' );
if( !s || strcmp( s, "?wsdl" ) )

{
return SOAP_GET_METHOD;
}

fd = fopen(".\\Server.wsdl", "rb"); //open WSDL file to copy

if (!fd)

{

return 404; //return HTTP not found error

}

soap->http_content = "text/xml";  //HTTP header with text /xml content

soap_response(soap,SOAP_FILE);

for(;;)

{

size_t r = fread(soap->tmpbuf,1, sizeof(soap->tmpbuf), fd);

if (!r)

{

break;

}

if (soap_send_raw(soap, soap->tmpbuf, r))

{

break; //cannot send, but little we can do about that

}

}

fclose(fd);

soap_end_send(soap);

return SOAP_OK;

}

多线程服务器设计实例:

1、通过获取wsdl生成头文件

dos界面下键入:

wsdl2h -c -s -o F:\学习资料\gsoap\demo\general\calc.h http://www.genivia.com/calc.wsdl

说明

wsdl2h可以加上完整路径,本机由于加入到了环境变量,所以无需绝对路径。

F:\学习资料\gsoap\demo\general\路径下将会生成calc.h头文件。

 

头文件里面包含信息

//gsoap ns2  service name: calc

//gsoap ns2  service type: calcPortType

//gsoap ns2  service port: http://websrv.cs.fsu.edu/~engelen/calcserver.cgi

//gsoap ns2  service namespace: urn:calc

//gsoap ns2  service transport: http://schemas.xmlsoap.org/soap/http

//gsoap ns2   schema namespace: urn:calc

//gsoap ns2   schema form: unqualified

 

//gsoap ns2  service method-protocol: add SOAP

//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 ""

//gsoap ns2  service method-output-action: add Response

 

自定义信息:

//gsoap ns service name: Test  

//gsoap ns service namespace: http://202.115.52.165:4567/Test.wsdl  

//gsoap ns service location: http://202.115.52.165:4567

//gsoap ns service executable: Test.cgi  

//gsoap ns service encoding: encoded  

//gsoap ns schema namespace: urn:Test

int ns2__add(double a,double b,double *result);

int ns2__sub(double a,double b,double *result);

int ns2__mul(double a,double b,double *result);

int ns2__div(double a,double b,double *result);

int ns2__pow(double a,double b,double *result);

2、生成服务端和客户端框架代码

dos界面键入:

soapcpp2 -2 -l -d F:\学习资料\gsoap\demo\general\ F:\学习资料\gsoap\demo\general\calc.h

说明:

-2 soap2绑定 –l 不生成lib文件 –d 输出路径  最后是你的头文件路径

3、创建服务端工程

步骤:

初始化soap

绑定IP和端口

等待连接

处理请求

释放资源

还需要实现自己发布方法的逻辑,在soapStub.h文件里面有包含了方法名一般由SOAP_FMAC5 int SOAP_FMAC6打头

4 创建客户端工程

创建soap,并初始化

调用webserver方法

最后释放资源

struct soap add_soap;

soap_init(&add_soap);

int result = -1;

char* server = "http://202.115.52.176:4567";

double a = 1.2;

double b = 1.3;

double res=0;

soap_call_ns2__add(&add_soap, server, "", a, b, &res);

if (add_soap.error)

{

std::cout << "soap error:" << add_soap.error << "," << *soap_faultcode(&add_soap) << "," << *soap_faultstring(&add_soap) << std::endl;

res = add_soap.error;

return 0;

}

std::cout << a << "+" << b << "=" <<res<< std::endl;

soap_end(&add_soap);

代码工程链接:http://download.csdn.net/detail/hl2015222050145/9622515

 

gsoap学习心得体会:

1gsoap即作客户端又作服务端的时候服务端头文件得加命名空间。不然会重定义

2、注意:此过程中要检查生成的编译信息,确保没有警告信息出现(警告信息可能是gSoap不支持的内容,如果不去除,程序运行故障很难找到根本原因),另不能只看编译结果成功就认为是正确的,存在警告信息也显示为编译成功!!

3、自己编写.h文件名的时候不要出现什么gsoap名字,因为gsoapsoapcpp2工具生成的文件会自动加上soap.否则很丑。

4、注意代码中的网址如http://127.0.0.1:8086,其中的http后只有一个冒号。

5 class SOAP_CMAC ServerDemoService : public soap //soap 只是一个结构体不是一个类

6//system("pause");//好像加与不加并没有什么区别

 


注:

由于笔者水平有限,若博文中存在错误或不周之处,还望各位大牛多多指教,有新的经验的时候也会及时更新本博文,谢谢! 

本篇博文为自己学习过程的心得笔记,如有内容雷同,还请见谅,谢谢!

 

 



  • 8
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用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工具的详细用法,并根据实际情况进行适当的配置和定制。 希望这些信息对你有所帮助!如果你有进一步的问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值