gsoap初始化释放_gsoap中文文档(下)

本文档详细介绍了如何使用gSOAP预编译器为C++客户端生成代理类,包括服务地址、命名空间和SOAPAction的定义。此外,还探讨了XSD类型编码,展示了如何将C++类型转换为XSD类型以便于互操作性。通过示例展示了如何创建、初始化和使用代理类,以及如何处理多个输出参数和匿名参数。最后,讨论了无输入和无输出参数的方法定义。
摘要由CSDN通过智能技术生成

8.1.4 如何建立客户端程序代理类

用于C++客户端程序的代理类信息是由gSOAP预编译器自动创建的。为了说明代理类的生成过程,我们在getQuote.h头文件中加入一些信息,以便gSOAP预编译器可以生成代理类。这些信息就类似于WSDL解析器自动生成的头文件中就已经包含的信息。

//"getQuote.h"的内容:

//gsoap ns1 service name: Quote

//gsoap ns1 service location: http://services.xmethods.net/soap

//gsoap ns1 service namespace: urn:xmethods-delayed-quotes

//gsoap ns1 service style: rpc

//gsoap ns1 service encoding: encoded

//gsoap ns1 service method-action: getQuote ""

int ns1__getQuote(char *symbol, float &Result);

前三行指令用于定义代理类的名称,服务地址,命名空间。第四行、第五行指令定义了使用SOAP RPC编码方式。最后一行定义了可选的SOAPAction。当需要SOAPAction时,这行信息将提供给每个远程方法。使用soapcpp2对该头文件进行编译后,将会产生soapQuoteProxy.h文件。它包含下面的内容:

#include "soapH.h"

class Quote

{ public:

struct soap *soap;

const char *endpoint;

Quote() { soap = soap_new(); endpoint = "http://services.xmethods.net/soap"; };

~Quote() { if (soap) { soap_destroy(soap); soap_end(soap); soap_done(soap); free((void*)soap); }};

int getQuote(char *symbol, float &Result) { return soap ? soap_call_ns1__getQuote(soap, endpoint, "", symbol, Result) : SOAP_EOM; };

};

为了能够在运行时刻对gSOAP环境变量及命名空间进行定制,上述两个变量被定义程全局变量。

生成的代理类可以同命名空间表一起包含在客户端程序中,请看下面的例子:

#include "soapQuoteProxy.h" // 获得代理类

#include "Quote.nsmap" // 获得命名空间绑定

int main()

{

Quote q;

float r;

if (q.ns1__getQuote("IBM", r) == SOAP_OK)

std::cout << r << std::endl;

else

soap_print_fault(q.soap, stderr);

return 0;

}

Quote构造函数定义并初始化了一个gSOAP运行环境实例。所有的HTTP及SOAP/XML进程都被隐藏在后台自动执行。

如果你需要多个命名空间表或要联合多个客户端,你可以在执行soapcpp2时添加参数-n及-p来生成命名空间表以防止冲突。详细信息请看9.1及18.33节。同时,你可以使用C++代码命名空间来创建一个命名空间限制的代理类,详细信息请看18.32节。

8.1.5 XSD 类型编码

许多SOAP服务需要在SOAP负载中使用XML编码。在gSOAP预编译器中使用的默认编码为SOAP RPC编码。然而,使用XSD类型编码可以改善互操作性。XSD类型在头文件中用typedef定义。举个例子,下面的定义将C/C++类型转换为XSD类型:

// Contents of header file:

...

typedef char *xsd__string; // encode xsd__string value as the xsd:string schema type

typedef char *xsd__anyURI; // encode xsd__anyURI value as the xsd:anyURI schema type

typedef float xsd__float; // encode xsd__float value as the xsd:float schema type

typedef long xsd__int; // encode xsd__int value as the xsd:int schema type

typedef bool xsd__boolean; // encode xsd__boolean value as the xsd:boolean schema type

typedef unsigned long long xsd__positiveInteger; // encode xsd__positiveInteger value as the xsd:positiveInteger schema type

...

这些简单的声明告诉gSOAP预编译器当远程方法参数中使用上述定义的类型时,就把相关的C++类型转当作内建的XSD类型进行编码、解码。同时,使用typedef不需要使用内建C++类型的客户端或服务端程序更改现有代码(但只是当参数为简单的C++类型时,请参看11.2.2节来使用XSD类型表示组合的数据类型)。

8.1.6 例子

重新考虑一席getQuote的例子。现在用XSD类型来重写代码:

// Contents of file "getQuote.h":

typedef char *xsd__string;

typedef float xsd__float;

int ns1__getQuote(xsd__string symbol, xsd__float &Result);

使用预编译器编译这个头文件,将会生成与原来相同的存根例程代码:

int soap_call_ns1__getQuote(struct soap *soap, char *URL, char *action, char *symbol, float &Result);

客户端程序不需要进行任何改动,即可使用XSD类型类编码、解码数据类型信息了。

举个例子,当客户端程序调用代理时,代理方法用xsd:string类型产生一个SOAP请求:

...

IBM

...

服务端的返回码为:

...

41.81

...

8.1.7 如何改变回传元素的名称

SOAP返回消息重的元素命名没有固定的方式,但是推荐使用方法名加Response结尾。例如,getQuote方法的返回参数为getQuoteResponse。

返回参数的名称可以在头文件中以类或结构体的方式声明。这个类或结构体的名字就是服务返回参数的名字。因此,远程方法的输出参数必须声明为类或结构体的一个(多个)字段。gSOAP预编译器可以自动生成用于存根例程使用的结构体或类。

8.1.8 例子

我们将getQuote远程方法的返回参数做如下的改变:

// Contents of "getQuote.h":

typedef char *xsd__string;

typedef float xsd__float;

struct ns1__getQuoteResponse {xsd__float Result;};

int ns1__getQuote(xsd__string symbol, struct ns1__getQuoteResponse &r);

输入参数还是和原来一样的:

...

IBM

...

不同的是输出参数必须符合getQuoteResponse的名称并有同样的命名空间:

...

41.81

...

类或结构体的定义也可以在函数内部进行,如:

// Contents of "getQuote.h":

typedef char *xsd__string;

typedef float xsd__float;

int ns1__getQuote(xsd__string symbol, struct ns1__getQuoteResponse {xsd__float Result;} &r);

8.1.9 如何指定多个输出参数

gSOAP预编译器将远程方法的最后一个参数作为输出参数,其余的参数都作为输入参数。如果要使用多个输出参数,就必须将输出参数定义为结构或类的形式。

8.1.10 例子

下面的例子中,getNames函数有个SSN作为输入参数,还有两个输出参数first及last。这个函数可以如下定义:

// Contents of file "getNames.h":

int ns3__getNames(char *SSN, struct ns3__getNamesResponse {char *first; char *last;} &r);

gSOAP将按照上述信息生成函数soap_call_ns3__getNames. 其请求信息为:

...

...

999 99 9999

...

输出信息为:

...

John

Doe

...

其中frist及last是远程方法的两个输出参数。

如果使用同一个变量作为输入、输出参数,也可以用结构体来定义。看下面的例子:

// Content of file "copy.h":

int X_rox__copy_name(char *name, struct X_rox__copy_nameResponse {char *name;} &r);

用类或结构体来定义为返回值,就可以定义上述输入、输出参数相同的远程方法。

gSOAP生成的请求信息如下:

...

...

SOAP

...

返回信息如下:

...

SOAP

...

8.1.11 如何将输出参数定义为类和结构体类型

如果远程方法唯一的返回参数使用类或结构体等复杂的数据类型,就必须在调用远程方法时使用类或结构作为返回元素。

8.1.12 例子

下面举个例子来说明一下。Flighttracker服务提供实时的航班信息。该服务需要一个航班代码及飞行号码作为输入参数。远程方法名字为getFlightInfo,它包含两个字符串参数:航班代码,飞行号码。这两个参数都必须用xsd:string编码作为参数类型。该远程方法返回一个getFlightResponse元素,其中包含一个复杂数据类型FlightInfo。FlightInfo类型在头文件中以类方式定义,他的字段信息与FlightInfo类型中的字段相同。

// Contents of file "flight.h":

typedef char *xsd__string;

class ns2__FlightInfo

{

public:

xsd__string airline;

xsd__string flightNumber;

xsd__string altitude;

xsd__string currentLocation;

xsd__string equipment;

xsd__string speed;

};

struct ns1__getFlightInfoResponse {ns2__FlightInfo return_;};

int ns1__getFlightInfo(xsd__string param1, xsd__string param2, struct ns1__getFlightInfoResponse &r);

返回元素ns1__getFlightInfoResponse中包含一个ns2__FlightInfo类型的字段return_。该字段以_结尾,以便和return关键字分别。详细信息请参看10.3节:将C++标识符转换为XML元素名。

gSOAP预编译器生成soap_call_ns1__getFlightInfo代理类。下面是一个客户端使用这个代理类的例子:

struct soap soap;

...

soap_init(&soap);

...

soap_call_ns1__getFlightInfo(&soap, "testvger.objectspace.com/soap/servlet/rpcrouter",

"urn:galdemo:flighttracker", "UAL", "184", r);

...

struct Namespace namespaces[] =

{

{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"},

{"SOAP-ENC","http://schemas.xmlsoap.org/soap/encoding/"},

{"xsi", "http://www.w3.org/2001/XMLSchema-instance"},

{"xsd", "http://www.w3.org/2001/XMLSchema"},

{"ns1", "urn:galdemo:flighttracker"},

{"ns2", "http://galdemo.flighttracker.com"},

{NULL, NULL}

};

客户端执行时,代理类生成如下请求信息:

POST /soap/servlet/rpcrouter HTTP/1.1

Host: testvger.objectspace.com

Content-Type: text/xml

Content-Length: 634

SOAPAction: "urn:galdemo:flighttracker"

xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:ns1="urn:galdemo:flighttracker"

xmlns:ns2="http://galdemo.flighttracker.com"

SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

UAL

184

Flighttracker服务返回:

HTTP/1.1 200 ok

Date: Thu, 30 Aug 2001 00:34:17 GMT

Server: IBM_HTTP_Server/1.3.12.3 Apache/1.3.12 (Win32)

Set-Cookie: sesessionid=2GFVTOGC30D0LGRGU2L4HFA;Path=/

Cache-Control: no-cache="set-cookie,set-cookie2"

Expires: Thu, 01 Dec 1994 16:00:00 GMT

Content-Length: 861

Content-Type: text/xml; charset=utf-8

Content-Language: en

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema">

SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

A320

UAL

188 mi W of Lincoln, NE

37000

497

184

代理类使用ns1__getFlightInfoResponse结构变量r来返回信息:

cout << r.return_.equipment << " flight " << r.return_.airline << r.return_.flightNumber

<< " traveling " << r.return_.speed << " mph " << " at " << r.return_.altitude

<< " ft, is located " << r.return_.currentLocation << endl;

上述代码将显示如下信息:

A320 flight UAL184 traveling 497 mph at 37000 ft, is located 188 mi W of Lincoln, NE

8.1.13 如何指定匿名参数名

SOAP1.1协议允许使用匿名参数。也就是说,远程方法的输出参数名不必与客户端的参数名严格保持一致。同样,远程方法的输入参数名也不必与客户端的参数名严格保持一致。虽然这种转换在SOAP1.2版本中不被提倡,但是gSOAP预编译器可以生成支持匿名参数的存根例程。只要在远程方法调用函数中的参数名称省略就可以使用匿名参数了。看下面的例子:

// Contents of "getQuote.h":

typedef char *xsd__string;

typedef float xsd__float;

int ns1__getQuote(xsd__string, xsd__float&);

要让参数名称在接收端匿名,在头文件定义函数时,参数名应该以下划线(_)开始。举个例子:

// Contents of "getQuote.h":

typedef char *xsd__string;

typedef float xsd__float;

int ns1__getQuote(xsd__string symbol, xsd__float &_return);

或者用一个结构体返回信息:

// Contents of "getQuote.h":

typedef char *xsd__string;

typedef float xsd__float;

struct ns1__getQuoteResponse {xsd__float _return;};

int ns1__getQuote(xsd__string symbol, struct ns1__getQuoteResponse &r);

在这个例子中,_return是个匿名输出参数。当服务回应该请求时,就可以使用任意的输出参数名称。输入参数名也可以是匿名的。这将影响web服务在gSOAP中的实现以及服务中参数名称的对应关系。

如果使用匿名参数,则函数定义中的参数顺序必须与所调用服务的参数顺序保持一致。

8.1.14 如何定义没有输入参数的方法

要定义一个没有输入参数的方法,只需要在函数定义中只保留一个参数作为输出参数就可以了。但是,某些C/C++编译器不能够编译空结构体(该结构体是gSOAP生成存储SOAP请求信息用)。这样,我们指定一个输入参数,使其类型为void*(gSOAP不能序列化void* 数据)。举个例子:

struct ns3__SOAPService

{

public:

int ID;

char *name;

char *owner;

char *description;

char *homepageURL;

char *endpoint;

char *SOAPAction;

char *methodNamespaceURI;

char *serviceStatus;

char *methodName;

char *dateCreated;

char *downloadURL;

char *wsdlURL;

char *instructions;

char *contactEmail;

char *serverImplementation;

};

struct ArrayOfSOAPService {struct ns3__SOAPService *__ptr; int __size;};

int ns__getAllSOAPServices(void *_, struct ArrayOfSOAPService &_return);

ns__getAllSOAPServices 方法包含一个void*类型的输入参数,它不会被gSOAP做序列化处理。多数的C/C++编译器允许空的结构体,所以void*类型的参数就不必使用了。

8.1.15 如何定义没有输出参数的方法

要指定一个没有输出参数的方法,需要将输出参数类型定义为一个空的结构体指针。

enum ns__event { off, on, stand_by };

int ns__signal(enum ns__event in, struct ns__signalResponse { } *out);

因为输出结构体为空,所以就没有输出参数了。如果编译器不支持空结构体,就指定一个包含void*类型变量的结构体。

有些SOAP资源用空的输出参数作为单向SOAP消息使用。但是,我们使用异步调用方式来支持单向消息。我们将在8.3节中详细讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值