gSOAP编译工具提供了一个SOAP/XML 关于C/C++ 语言的实现,在数据接入其他平台,如C#、JAVA实现的一些webservice服务,在需要将数据对接其他设备的应用中,gSOAP可以为开发提供很大方便。
一般的,一个webservice服务端,会提供一个wsdl文件、一个接入的url地址和一份对应的字段定义文档,有了这些资料,就可以使用gSOAP进行webservice对接。
关于gSOAP的安装、部署、这里不做介绍,网上有很多相应的指导方法。
在进行对接之前,首先要明确服务端使用的是soap1.1还是soap1.2,通常soap1.2可以兼容soap1.1,反之不行。
gSOAP工具包中,有2个文件wsdl2h和soapcpp2,这两个工具文件用来根据wsdl文件反编译出一套代码,代码中含有服务的接口、以及接口对应的各个字段,可以根据需求生成c或c++的代码,在自己的代码中,将需要传输到服务端的字段拼装后,即可调用接口进行数据的传输。
反编译代码步骤:
1.使用wsdl2h工具,根据wsdl文件生成一个c/c++语法结构的头文件
Wsdl2h–s –o 头文件名 wsdl文件名
这一步将会得到一个头文件,如:head.h该步的目的:实现WSDL文件到.h文件的数据映射。
2.使用gSoap的预编译器soapcpp2。
根据上一步得到的头文件来生成存根文件(soapStub.h)和客户端代码框架。
/usr/local/gSOAP/bin/soapcpp2-i -x -C -L head.h
这一步将会得到几个.nsmap、.h和.cpp文件,如:calc.nsmap、soapC.cpp、soapH.h、soapStub.h、soapcalcProxy.cpp、soapcalcProxy.h
该步的目的:生成相应的底层通信代码。
注1 :wsdl2h的用法(WSDL/schema 解析和代码生成器)wsdl2h [opt] 头文件名 WSDL文件名或URL
wsdl2h常用选项
-o 文件名,指定输出头文件
-n 名空间前缀 代替默认的ns
-c 产生纯C代码,否则是C++代码
-s 不要使用STL代码
-t 文件名,指定type map文件,默认为typemap.dat
-e 禁止为enum成员加上名空间前缀
type map文件用于指定SOAP/XML中的类型与C/C++之间的转换规则。
如果不用s就会生成带STL的头文件,这样,在后边的编译中需要加入STL的头
stlvector.h,位于:gsoap/import/目录下。
注2 :soapcpp2的用法(编译和代码生成器)
soapcpp2 [opt] 头文件名
soapcpp2常用选项
-C 仅生成客户端代码
-S 仅生成服务器端代码
-L 不要产生soapClientLib.c和soapServerLib.c文件
-c 产生纯C代码,否则是C++代码(与头文件有关)
-I 指定import路径(见上文)
-x 不要产生XML示例文件
-i 生成C++封装(代理),客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)。
本例中,使用的是:soapcpp2 -i -x -C -L calc.h
注3 :gSoap工具wsdl2和soapcpp所生成文件的简单分析
(1) wsdl2生成的具有C/C++语法结构的头文件,其作用就是:将XML语法结构的WSDL文件映射为C/C++语法结构的.h文件;并为下一步做准备。
(2) soapcpp(采用参数:-i -x -C -L)生成的文件共有6个文件:PlayerBeanPortBinding.nsmap、soapC.cpp、soapH.h、soapPlayerBeanPortBindingProxy.cpp、soapPlayerBeanPortBindingProxy.h、soapStub.h。
a. PlayerBeanPortBinding.nsmap文件
该文件的作用:An XML-to-C/C++ namespace mapping table,即WSDL文件与生成的客户端代码框架的一个名字空间的映射表。
b. soapStub.h
该文件就是直接由wsdl2生成的头文件转化而来,它详细定义了WSDL所描述的各项服务和数据结构。
它是soap的存根文件,定义了由wsdl2生成的头文件里对应的远程调用模型(RPC)。
c. soapPlayerBeanPortBindingProxy.和soapPlayerBeanPortBindingProxy.cpp
这两个文件是客户端代码的一个简单封装,它封装了底层通信,并向外提供一个很简单的界面,该界面展示了用户能够使用的所有服务(由WSDL所描述)。
d. soapH.h和soapC.cpp
这个两个文件是soap的序列和反序列化代码,
注4 :设置字符编码
在利用gSoap编写Web Service客户端和服务器端的程序时,需要设置其编码方式。接口为:soap_set_mode,其实它是就是一个宏:
#define soap_set_mode(soap, n) ((soap)->imode |= (n),(soap)->omode |= (n))
如果要设置为UTF8
可以这样调用:soap_set_mode(&soap,SOAP_C_UTFSTRING);
详细信息可参考该宏所在文件:stdsoap2.h
示例1:使用c调用gSOAP实现webservice通信
用上述方法反编译生成的接口函数如下:
SOAP_FMAC5 int SOAP_FMAC6 soap_call___ns4__InPeccancyInfo(struct soap *soap, const char *soap_endpoint, const char *soap_action, struct _ns2__InPeccancyInfo *ns2__InPeccancyInfo, struct _ns2__InPeccancyInfoResponse *ns2__InPeccancyInfoResponse)
{ struct __ns4__InPeccancyInfo soap_tmp___ns4__InPeccancyInfo;
if (!soap_endpoint)
soap_endpoint = "http://localhost:13059/Ehl.Atms.Tgs.WebService/VcpService.asmx";
if (!soap_action)
soap_action = "http://tempuri.org/InPeccancyInfo";
soap->encodingStyle = NULL;
soap_tmp___ns4__InPeccancyInfo.ns2__InPeccancyInfo = ns2__InPeccancyInfo;
soap_begin(soap);
soap_serializeheader(soap);
soap_serialize___ns4__InPeccancyInfo(soap, &soap_tmp___ns4__InPeccancyInfo);
if (soap_begin_count(soap))
return soap->error;
if (soap->mode & SOAP_IO_LENGTH)
{ if (soap_envelope_begin_out(soap)
|| soap_putheader(soap)
|| soap_body_begin_out(soap)
|| soap_put___ns4__InPeccancyInfo(soap, &soap_tmp___ns4__InPeccancyInfo, "-ns4:InPeccancyInfo", NULL)
|| soap_body_end_out(soap)
|| soap_envelope_end_out(soap))
return soap->error;
}
if (soap_end_count(soap))
return soap->error;
if (soap_connect(soap, soap_endpoint, soap_action)
|| soap_envelope_begin_out(soap)
|| soap_putheader(soap)
|| soap_body_begin_out(soap)
|| soap_put___ns4__InPeccancyInfo(soap, &soap_tmp___ns4__InPeccancyInfo, "-ns4:InPeccancyInfo", NULL)
|| soap_body_end_out(soap)
|| soap_envelope_end_out(soap)
|| soap_end_send(soap))
return soap_closesock(soap);
if (!ns2__InPeccancyInfoResponse)
return soap_closesock(soap);
soap_default__ns2__InPeccancyInfoResponse(soap, ns2__InPeccancyInfoResponse);
if (soap_begin_recv(soap)
|| soap_envelope_begin_in(soap)
|| soap_recv_header(soap)
|| soap_body_begin_in(soap))
return soap_closesock(soap);
soap_get__ns2__InPeccancyInfoResponse(soap, ns2__InPeccancyInfoResponse, "ns2:InPeccancyInfoResponse", "");
if (soap->error)
return soap_recv_fault(soap, 0);
if (soap_body_end_in(soap)
|| soap_envelope_end_in(soap)
|| soap_end_recv(soap))
return soap_closesock(soap);
return soap_closesock(soap);
}
调用该接口函数的代码:
#include
struct soap m_SoapClient
int main()
{
int ret = -1;
memset(&m_SoapClient, 0, sizeof(struct soap));
soap_init(&m_SoapClient);
soap_set_mode(&m_SoapClient, SOAP_C_UTFSTRING);
struct soap *pSoapTemp = NULL;
pSoapTemp = &m_SoapClient;
struct _ns2__InPeccancyInfo ns2__InPeccancyInfo;
struct _ns2__InPeccancyInfoResponse ns2__InPeccancyInfoResponse;
memset(&ns2__InPeccancyInfo,0,sizeof(struct _ns2__InPeccancyInfo));
memset(&ns2__InPeccancyInfoResponse,0,sizeof(struct _ns2__InPeccancyInfoResponse));
ret = soap_call___ns4__InPeccancyInfo(pSoapTemp, (const char*)urlPeccancy, NULL, &ns2__InPeccancyInfo, &ns2__InPeccancyInfoResponse);
if (SOAP_OK != ret)
{
printf("call soap OK!\n");
}
else
{
printf("call soap failed!\n");
}
soap_destroy(pSoapTemp);
soap_end(pSoapTemp);
soap_done(pSoapTemp);
return ret;
}
示例2:使用c++调用gSOAP实现webservice通信
编译生成的gSOAP接口函数如下:
class SOAP_CMAC VcpServiceSoap12Proxy : public soap
{ public:
/// Endpoint URL of service 'VcpServiceSoap12Proxy' (change as needed)
const char *soap_endpoint;
/// Constructor
VcpServiceSoap12Proxy();
/// Construct from another engine state
VcpServiceSoap12Proxy(const struct soap&);
/// Constructor with endpoint URL
VcpServiceSoap12Proxy(const char *url);
/// Constructor with engine input+output mode control
VcpServiceSoap12Proxy(soap_mode iomode);
/// Constructor with URL and input+output mode control
VcpServiceSoap12Proxy(const char *url, soap_mode iomode);
/// Constructor with engine input and output mode control
VcpServiceSoap12Proxy(soap_mode imode, soap_mode omode);
/// Destructor frees deserialized data
virtual ~VcpServiceSoap12Proxy();
/// Initializer used by constructors
virtual void VcpServiceSoap12Proxy_init(soap_mode imode, soap_mode omode);
/// Delete all deserialized data (uses soap_destroy and soap_end)
virtual void destroy();
/// Delete all deserialized data and reset to default
virtual void reset();
/// Disables and removes SOAP Header from message
virtual void soap_noheader();
/// Get SOAP Header structure (NULL when absent)
virtual const SOAP_ENV__Header *soap_header();
/// Get SOAP Fault structure (NULL when absent)
virtual const SOAP_ENV__Fault *soap_fault();
/// Get SOAP Fault string (NULL when absent)
virtual const char *soap_fault_string();
/// Get SOAP Fault detail as string (NULL when absent)
virtual const char *soap_fault_detail();
/// Close connection (normally automatic, except for send_X ops)
virtual int soap_close_socket();
/// Force close connection (can kill a thread blocked on IO)
virtual int soap_force_close_socket();
/// Print fault
virtual void soap_print_fault(FILE*);
#ifndef WITH_LEAN
/// Print fault to stream
#ifndef WITH_COMPAT
virtual void soap_stream_fault(std::ostream&);
#endif
/// Put fault into buffer
virtual char *soap_sprint_fault(char *buf, size_t len);
#endif
/// Web service operation 'InViolation' (returns error code or SOAP_OK)
virtual int InViolation(_ns2__InViolation *ns2__InViolation, _ns2__InViolationResponse *ns2__InViolationResponse) { return InViolation(NULL, NULL, ns2__InViolation, ns2__InViolationResponse); }
virtual int InViolation(const char *endpoint, const char *soap_action, _ns2__InViolation *ns2__InViolation, _ns2__InViolationResponse *ns2__InViolationResponse);
};
int VcpServiceSoap12Proxy::InViolation(const char *endpoint, const char *soap_action, _ns2__InViolation *ns2__InViolation, _ns2__InViolationResponse *ns2__InViolationResponse)
{ struct soap *soap = this;
struct __ns4__InViolation soap_tmp___ns4__InViolation;
if (endpoint)
soap_endpoint = endpoint;
if (!soap_endpoint)
soap_endpoint = "http://localhost/Ehl.Atms.Tgs.WebService/VcpService.asmx";
if (!soap_action)
soap_action = "http://tempuri.org/InViolation";
soap->encodingStyle = NULL;
soap_tmp___ns4__InViolation.ns2__InViolation = ns2__InViolation;
soap_begin(soap);
soap_serializeheader(soap);
soap_serialize___ns4__InViolation(soap, &soap_tmp___ns4__InViolation);
if (soap_begin_count(soap))
return soap->error;
if (soap->mode & SOAP_IO_LENGTH)
{ if (soap_envelope_begin_out(soap)
|| soap_putheader(soap)
|| soap_body_begin_out(soap)
|| soap_put___ns4__InViolation(soap, &soap_tmp___ns4__InViolation, "-ns4:InViolation", NULL)
|| soap_body_end_out(soap)
|| soap_envelope_end_out(soap))
return soap->error;
}
if (soap_end_count(soap))
return soap->error;
if (soap_connect(soap, soap_endpoint, soap_action)
|| soap_envelope_begin_out(soap)
|| soap_putheader(soap)
|| soap_body_begin_out(soap)
|| soap_put___ns4__InViolation(soap, &soap_tmp___ns4__InViolation, "-ns4:InViolation", NULL)
|| soap_body_end_out(soap)
|| soap_envelope_end_out(soap)
|| soap_end_send(soap))
return soap_closesock(soap);
if (!ns2__InViolationResponse)
return soap_closesock(soap);
ns2__InViolationResponse->soap_default(soap);
if (soap_begin_recv(soap)
|| soap_envelope_begin_in(soap)
|| soap_recv_header(soap)
|| soap_body_begin_in(soap))
return soap_closesock(soap);
ns2__InViolationResponse->soap_get(soap, "ns2:InViolationResponse", "");
if (soap->error)
return soap_recv_fault(soap, 0);
if (soap_body_end_in(soap)
|| soap_envelope_end_in(soap)
|| soap_end_recv(soap))
return soap_closesock(soap);
return soap_closesock(soap);
}
其中,接口函数InViolation被封装在一个类VcpServiceSoap12Proxy中,因而,要调用该接口函数,需要先初始化一个VcpServiceSoap12Proxy类
调用该接口的函数:
#include "soapVcpServiceSoap12Proxy.h"
int main()
{
VcpServiceSoap12Proxy *pSoapVcpServiceProxy;
_ns2__InViolation peccancyCarInfo;
_ns2__InViolationResponse peccancyCarInfoRes;
pSoapVcpServiceProxy = new VcpServiceSoap12Proxy(urlPeccancy, SOAP_C_UTFSTRING);
ret = pSoapVcpServiceProxy->InViolation(urlPeccancy, NULL, &peccancyCarInfo, &peccancyCarInfoRes);
if(SOAP_OK != ret)
{
delete pSoapVcpServiceProxy;
return ERROR;
}
delete pSoapVcpServiceProxy;
return ret;
}