linux下利用gsoap实现webservice通信方法详解

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;
}





你可能感兴趣的:(c/c++,网络编程/多线程,Webservice)