本文中使用的gSoap版本是2.8.17的,采用的编译器是VS2008。下面先简要介绍下gSoap的相关知识。
一、gSoap基础知识简介
wsdl2h常用选项
- -o 文件名,指定输出头文件
- -n 名空间前缀 代替默认的ns
- -c 产生纯C代码,否则是C++代码
- -s 不要使用STL代码
- -t 文件名,指定type map文件,默认为typemap.dat
- -e 禁止为enum成员加上名空间前缀
2.2 soapcpp2
soapcpp2的使用方法:
<span style="font-weight: normal;"><span style="font-family:SimSun;font-size:18px;">soapcpp2 头文件.h</span></span><span style="font-weight: normal;"><span style="font-family:SimSun;font-size:18px;">soapcpp2 ayandy.h</span></span>将生成下面这些文件
- soapStub.h // soap的存根文件,定义了ayandy.h里对应的远程调用模型
- soapC.c soapH.h // soap的序列和反序列代码,它已经包含了soapStub.h,服务器端与客户端都要包含它
- soapClient.c soapClientLib.c // 客户端代码,soapClientLib.c文件则只是简单地包含soapClient.c和soapC.c
- soapServer.c soapServerLib.c // 服务器端代码,soapServerLib.c文件则只是简单地包含soapServer.c和soapC.c
- ServiceSoap.nsmap ServiceSoap12.nsmap // 名空间定义,服务器端与客户端都要包含它
- soapServiceSoapProxy.h soapServiceSoap12Proxy.h // 客户端的C++简单包装(如果头文件是纯C代码,这两个文件就不会生成)
soapcpp2常用选项
- -C 仅生成客户端代码
- -S 仅生成服务器端代码
- -L 不要产生soapClientLib.c和soapServerLib.c文件
- -c 产生纯C代码,否则是C++代码(与头文件有关)
- -I 指定import路径(见上文)
- -x 不要产生XML示例文件
- -i 生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)。
三、gSoap使用实例
本例中gSoap的目录D:\Language\gsoap\gsoap-2.8
3.1.Web Service服务端(C++)
3.2 WebService客户端(C++语言)[1]新建空的Win32控制台项目“MyFirstWS”。然后添加一个头文件“MyInterface.h”,输入你要暴露给WS客户端的方法声明,内容如下
int ns__sqrt(double a, double &result);
[2]将D:\Language\gsoap\gsoap-2.8\gsoap\bin\win32中soapcpp2.exe复制到新建的win32项目目录中,在CMD中打开win32项目文件夹,运行命令“soapcpp2 -S MyInterface.h”生成存根文件
将新生成的C++的源码文件加入到你的工程项目中,soapServerLib.cpp文件不用加。你需要修改自动生成的ns.wsdl文件(可用Notepad等方式打开该文件,在文件的末端可以找到侦听的端口),因为里面的Web Service侦听端口默认为80,但是我们一般不使用默认侦听端口。
[3]加入“D:\Language\gsoap\gsoap-2.8\gsoap”下的“stdsoap2.h、stdsoap2.cpp、dom.cpp(可不要)”三个源文件到当前项目中。
[4]添加一个源文件,命名为:MyFirstWS.cpp,源文件内容如下
// MyFirstWS.cpp : Defines the entry point for the console application. // #include <tchar.h> #include "MyInterface.h" #include "ns.nsmap" //我的接口实现 int ns__sqrt(struct soap *soap, double a, double &result) { if (a >= 0) { result = sqrt(a); return SOAP_OK; } return soap_sender_fault(soap, "Square root of negative value", "I can only compute the square root of a non-negative value"); } //返回接口描述,否则在为C#代码添加服务引用时,找不到这个接口 int http_get(struct soap *soap) { std::string fileName = "ns.wsdl"; if(strstr(soap->msgbuf,"clientaccesspolicy.xml")!=NULL){ fileName = "clientaccesspolicy.xml"; }//红色乃添加的代码 FILE*fd = NULL; fd = fopen(fileName.c_str(), "rb"); //open WSDL file to copy if (!fd) { return 404; //return HTTP not found error } soap->http_content = "text/xml"; //HTTP header with text /xml content soap_response(soap,SOAP_FILE); for(;;) { size_t r = fread(soap->tmpbuf,1, sizeof(soap->tmpbuf), fd); if (!r) { break; } if (soap_send_raw(soap, soap->tmpbuf, r)) { break; //cannot send, but little we can do about that } } fclose(fd); soap_end_send(soap); return SOAP_OK; } int _tmain(int argc, _TCHAR* argv[]) { int m, s; /* master and slave sockets */ //初始化soap环境变量 struct soap sqrt_soap; soap_init(&sqrt_soap); //添加,返回接口描述(WSDL)的功能, //否则其它语言在建立Web Service客户端的时候,无法自动生成代码 sqrt_soap.fget = http_get; //服务端侦听端口设为8080,注意ns.wsdl文件内容要做相应修改 m = soap_bind(&sqrt_soap, NULL, 8080, 100); if (m < 0) { soap_print_fault(&sqrt_soap, stderr); exit(-1); } fprintf(stderr, "Socket connection successful: master socket = %d\n", m); for ( ; ; ) { s = soap_accept(&sqrt_soap); if (s < 0) { soap_print_fault(&sqrt_soap, stderr); exit(-1); } fprintf(stderr, "Socket connection successful: slave socket = %d\n", s); soap_serve(&sqrt_soap); soap_end(&sqrt_soap); } return 0; }
[1]新建C++的Console工程,运行3.1中创建的WebService服务端(这步很重要)
[2]将gSoap中的wsdl2h.exe和soapcpp2.exe复制到新建工程目录中,根据http://localhost:8080/网址打印出的WSDL信息产生MyInterface.h头文件,在CMD中打开新建工程的目录文件夹,然后输入下面命令
wsdl2h -o MyInterface.h http://localhost:8080/
[3]根据“MyInterface.h”头文件生成存根文件
soapcpp2 -i -C -I D:\Language\gsoap\gsoap-2.8\gsoap\import MyInterface.h
“-C”参数指定只生成客户端存根文件,默认服务端和客户端存根文件都生成。“-I”参数指定stlvector.h文件的搜索路径。“D:\Language\gsoap\gsoap-2.8\gsoap\import”是我gsoap Toolkit的存放路径。在项目中添加新生成的源文件,soapClientLib.cpp文件不用添加。
[4]在项目中添加D:\Language\gsoap\gsoap-2.8\gsoap\目录下的stdsoap2.h、stdsoap2.cpp、dom.cpp三个文件。
[5]修改项目默认的cpp文件,源码清单如下
// MyFirstWSClient.cpp : Defines the entry point for the console application. // //服务端提供的功能可以查看下面的头文件内容 //如果服务端的URL地址或侦听端口改变,需要修改下面这个头文件 #include "soapServiceProxy.h" //下面这个头文件是必须的,否则stdsoap2.obj连接的时候会出错 #include "Service.nsmap" #include <tchar.h> int _tmain(int argc, _TCHAR* argv[]) { ServiceProxy srv; double dR; _ns2__sqrt call; //形参表 _ns2__sqrtResponse response; //返回调用结果 call.a = 4.0; int nR = srv.sqrt(&call,&response);//调用sqrt函数 if( nR == SOAP_OK) { dR = response.result; printf("成功返回,sqrt(4)=%f\n",response.result); } else { printf("请检查网络连接!"); } while(1); return 0; }