天天看点

gSoap例子学习(一)

由于工作需要,故特意学习了一下gSoap,并记录下学习笔记,供自己后续复习用。(文中如有任何不对的,请网友指出,本人感激不尽)

下载gSoap工具,下载链接:http://sourceforge.jp/projects/sfnet_gsoap2/releases/

我下载的是,当前最新gsoap_2.8.17版本,由于习惯用windows,下了一个zip文件,相应的解压缩后,即可使用。

gSoap简介

此处引用:http://www.360doc.com/content/13/0121/10/10453810_261511140.shtml

gSOAP编译工具提供了一个SOAP/XML关于C/C++语言的实现,从而让C/C++语言开发web服务或客户端程序的工作变得轻松了很多。绝大多数的C++web服务工具包提供一组API函数类库来处理特定的SOAP数据结构,这样就使得用户必须改变程序结构来适应相关的类库。与之相反,gSOAP利用编译器技术提供了一组透明化的SOAP API,并将与开发无关的SOAP实现细节相关的内容对用户隐藏起来。gSOAP的编译器能够自动的将用户定义的本地化的C或C++数据类型转变为符合XML语法的数据结构,反之亦然。这样,只用一组简单的API就将用户从SOAP细节实现工作中解脱了出来,可以专注与应用程序逻辑的实现工作了。gSOAP编译器可以集成C/C++和Fortran代码(通过一个Fortran到C的接口),嵌入式系统,其他SOAP程序提供的实时软件的资源和信息;可以跨越多个操作系统,语言环境以及在防火墙后的不同组织。

gSOAP使编写web服务的工作最小化了。gSOAP编译器生成SOAP的代码来序列化或反序列化C/C++的数据结构。gSOAP包含一个WSDL生成器,用它来为你的web服务生成web服务的解释。gSOAP的解释器及导入器可以使用户不需要分析web服务的细节就可以实现一个客户端或服务端程序。

简言之,gSoap可以为我们生成soap服务端+客户端代码的框架,我们只需要实现具体的接口函数即可。而生成代码的工具,就是这个gSoap编译器工具。

gSoap中两个重要工具介绍

1. wsdl2h

该工具的主要功能是,通过wsdl文件生成C/C++ .h头文件

用法例子:

wsdl2h -o头文件名 WSDL文件名或URL

常用的其它参数:

-o文件名,指定输出头文件

-n名空间前缀 代替默认的ns

-c产生纯C代码,否则是C++代码

-t文件名,指定type map文件,默认为typemap.dat

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

2. socapcpp2

此工具用来从头文件,生成SOAP服务器及客户端代码,还包括WSDL、测试用XML数据

常用选项

-C仅生成客户端代码

-S仅生成服务器端代码

-L不要产生soapClientLib.c和soapServerLib.c文件

-c产生纯C代码,否则是C++代码(与头文件有关)

-I指定import路径

-x不要产生XML示例文件

-i生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)

gSoap例子学习

在gsoap目录中有个calc的例子,可供我们初学者进行学习。

在D:\gsoap_2.8.17\gsoap-2.8\gsoap\samples\calc++目录下,另外一个calc是C语言版本,我这用的是C++版本。

1.生成头文件

先获取calc的wsdl文件,在calc.h中,有 //gsoap ns service namespace:   http://websrv.cs.fsu.edu/~engelen/calc.wsdl

该链接就是我们要的wsdl文件的url. 

我在D盘创建了一个calc-demo文件夹

用wsdl2h.exe生成对应的.h头文件(我这边用的是C++的)

gSoap例子学习(一)
gSoap例子学习(一)

即,wsdl2h.exe–o calc.h对应url,但是会报错。其实你现在去查看目录中的calc.h,对应的内容都已经生成,我实验过,用该.h运行后续的,没什么问题,当然本着“知错就改”的态度,我们还是要解决下这个问题的。上述问题,是由于缺失typemap.dat文件所造成,在D:\gsoap_2.8.17\gsoap-2.8\gsoap目录中,有该typemap.dat文件,将typemap.dat拷贝到当前目录calc-demo就可以了,再运行一次,就无错通过了。生成的calc.h与之前报错时,生成的是一样的....

2.生成.cpp及nsmp文件

得到calc.h头文件后,我们需要用soapcpp2.exe,获取对应的cpp,nsmp文件

gSoap例子学习(一)
gSoap例子学习(一)

即cmd在当前目录calc-demo下(生成的文件都会在该目录下),命令为:soapcpp2.exe calc.h -I D:\gsoap_2.8.17\gsoap-2.8\gsoap\import

后面的-I D:\gsoap_2.8.17\gsoap-2.8\gsoap\import是因为,编译中要用到"stlvector.h",该文件在D:\gsoap_2.8.17\gsoap-2.8\gsoap\import,所以-I向编译器指定一下该目录,否则会提示出错找不到"stlvector.h"文件。

下图中红色框圈起来的,就是soapcpp2.exe新生成出来的,包括服务端、客户端的cpp都生成出来了。

gSoap例子学习(一)

3. client代码编写

在calc-demo目录下,创建一个控制台工程calc_client,新建文件client.cpp

client.cpp代码如下:

#include <stdio.h>
#include <stdlib.h>
#include "calc.nsmap"
#include "stdsoap2.h"

char* g_server="http://localhost:4567";

int sendRequest(const char reqType, double num1, double num2, double &result)
{
	struct soap send_soap;
	int ret = 0;
	soap_init(&send_soap);

	switch(reqType)
	{
		case 'a':
			{
				soap_call_ns2__add( &send_soap, g_server, "", num1, num2, result );
				if(send_soap.error)
				{
					printf("soap error:%d,%s,%s/n", send_soap.error, *soap_faultcode(&send_soap), *soap_faultstring(&send_soap) );
					ret = send_soap.error;
				}
				else
				{
					printf("[add] result = %lf\n", result);
				}				
			}
			break;
		case 's':
			{
				soap_call_ns2__sub( &send_soap, g_server, "", num1, num2, result );
				if(send_soap.error)
				{
					printf("soap error:%d,%s,%s/n", send_soap.error, *soap_faultcode(&send_soap), *soap_faultstring(&send_soap) );
					ret = send_soap.error;
				}
				else
				{
					printf("[sub] result = %lf\n", result);
				}				
			}
			break;
		case 'm':
			{
				soap_call_ns2__mul( &send_soap, g_server, "", num1, num2, result );
				if(send_soap.error)
				{
					printf("soap error:%d,%s,%s/n", send_soap.error, *soap_faultcode(&send_soap), *soap_faultstring(&send_soap) );
					ret = send_soap.error;
				}
				else
				{
					printf("[mul] result = %lf\n", result);
				}				
			}
			break;
		case 'd':
			{
				soap_call_ns2__div( &send_soap, g_server, "", num1, num2, result );
				if(send_soap.error)
				{
					printf("soap error:%d,%s,%s/n", send_soap.error, *soap_faultcode(&send_soap), *soap_faultstring(&send_soap) );
					ret = send_soap.error;
				}
				else
				{
					printf("[mul] result = %lf\n", result);
				}				
			}
			break;
		case 'p':
			{
				soap_call_ns2__pow( &send_soap, g_server, "", num1, num2, result );
				if(send_soap.error)
				{
					printf("soap error:%d,%s,%s/n", send_soap.error, *soap_faultcode(&send_soap), *soap_faultstring(&send_soap) );
					ret = send_soap.error;
				}
				else
				{
					printf("[mul] result = %lf\n", result);
				}				
			}
			break;
		default:
			{
				printf("not this opertion!\n");
			}
			break;
	}	
	soap_end(&send_soap);
	soap_done(&send_soap);
	return ret;
}

int main(int argc, char **argv)
{
	int ret = -1;
	double num1 = 0;
	double num2 = 0;
	double result = 0;	
	
	if (argc < 4)
	{ 
		fprintf(stderr, "Usage: [add|sub|mul|div|pow] num num\n");
		exit(0);
	}
	
	num1 = atoi(argv[2]);
	num2 = atoi(argv[3]);

	ret = sendRequest(*argv[1], num1, num2, result );	
	return ret;
}
           

拷贝soapC.cpp、soapClient.cpp、soapH、soapStub.h、calc.nsmap这几个文件到文件夹内。

拷贝D:\gsoap_2.8.17\gsoap-2.8\gsoap目录下的,stdsoap2.cpp、stdsoap2.h到calc_client文件夹,并将这几个文件都添加到工程中,

注意以下两点,不然可能会编译报错:

在project-setting-Link在Object/librarymodules后添加一个wsock32.lib。

在project-setting中将添加进来的3个源文件的C/C++选项的Category设置为PrecompiledHeaders。

准备完了,整体编译下,就OK了。

4. server代码编写

在calc-demo目录下,创建控制台工程calc_server,新建文件server.cpp

Server.cpp代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "stdsoap2.h"
#include "calc.nsmap"

int main(int argc, char* argv[])
{
	int m, s;
	struct soap add_soap;
	soap_init(&add_soap);

	if (argc < 2)
	{
		printf("usage: %s <server_port> /n", argv[0]);
		exit(1);
	}
	else
	{
		m = soap_bind(&add_soap, NULL, atoi(argv[1]), 100);
		if (m < 0)
		{
			soap_print_fault(&add_soap, stderr);
			exit(-1);
		}
		fprintf(stderr, "Socket connection successful: master socket = %d, server_port = %d/n", m, atoi(argv[1]));
		for ( ; ; )
		{
			s = soap_accept(&add_soap);
			if (s < 0)
			{
				soap_print_fault(&add_soap, stderr);
				exit(-1);
			}
			fprintf(stderr, "Socket connection successful: slave socket = %d/n", s);
			soap_serve(&add_soap);
			soap_end(&add_soap);
		}
	}
	return 0;
}
 
int ns2__add(struct soap *add_soap, double num1, double num2, double &result)
{	
	result = num1 + num2;
	printf("[add] num1 = %lf, num2 = %lf, result = %lf\n", num1, num2, result);
	return 0;
}

int ns2__sub(struct soap *add_soap, double num1, double num2, double &result)
{
	if(num1 > num2)
	{
		result = num1 - num2;
	}
	else
	{
		result = num2 - num1;
	}	
	printf("[sub] num1 = %lf, num2 = %lf, result = %lf\n", num1, num2, result);
	return 0;
}

int ns2__mul(struct soap *add_soap, double num1, double num2, double &result)
{
	result = num1 * num2;
	printf("[mul] num1 = %lf, num2 = %lf, result = %lf\n", num1, num2, result);
	return 0;
}

int ns2__div(struct soap *add_soap, double num1, double num2, double &result)
{
	result = num1 / num2;
	printf("[div] num1 = %lf, num2 = %lf, result = %lf\n", num1, num2, result);
	return 0;
}

int ns2__pow(struct soap *add_soap, double num1, double num2, double &result)
{
	result = pow((float)num1,(float)num2);
	printf("[div] num1 = %lf, num2 = %lf, result = %lf\n", num1, num2, result);
	return 0;
}
           

拷贝soapC.cpp、soapServer.cpp、soapH、soapStub.h、calc.nsmap这几个文件到文件夹内。

拷贝D:\gsoap_2.8.17\gsoap-2.8\gsoap目录下的,stdsoap2.cpp、stdsoap2.h到calc_server文件夹,并将这几个文件都添加到工程中。

注意以下两点,不然可能会编译报错:

在project-setting-Link在Object/librarymodules后添加一个wsock32.lib。

在project-setting中将添加进来的3个源文件的C/C++选项的Category设置为PrecompiledHeaders。

准备完了,整体编译下,就OK了。

5.调试结果

运行一个cmd跳到D:\calc-demo\calc_server\Debug下输入calc_server.exe 4567,启动服务端程序。

(如下图,在浏览器中,输入localhost:4567,能跳出如下页面,说明服务端已经启动成功了)

gSoap例子学习(一)
gSoap例子学习(一)
gSoap例子学习(一)

另运行一个cmd跳到D:\calc-demo\calc_client\Debug下输入calc_client.exe a 6 7,运行客户端程序。

gSoap例子学习(一)
gSoap例子学习(一)

结果为:[add] result = 13.000000

调试成功。

具体代码部分,在后面的笔记中,再详细说明。