由于工作需要,故特意学习了一下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++的)
即,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文件
即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都生成出来了。
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,能跳出如下页面,说明服务端已经启动成功了)
另运行一个cmd跳到D:\calc-demo\calc_client\Debug下输入calc_client.exe a 6 7,运行客户端程序。
结果为:[add] result = 13.000000
调试成功。
具体代码部分,在后面的笔记中,再详细说明。