因为项目中需要使用WebService,所以将webservice的有关东西温故了一下。以前采用C#,这几乎不成什么问题,毕竟C#与WebService几乎是同时火起来的,所以C#天然地支持webservice就不奇怪了。Java的情况大致与C#一样,C/C++就不同了,还好有gSOAP,就用一下吧。
一、gSOAP简介
gSOAP是一个开发SOAP和XML应用(它们组成了webservice)的工具,在英文中叫toolkit。它是跨平台的,webservice的客户端和服务器端,都可以用它来辅助开发。它主要的功能(特征)如下:
- C/C++数据绑定工具,支持XML-RPCfrom/to JSON from/to C/C++ serialization
- 支持WSDL 1.1,2.0, SOAP 1.1, 1.2
- 支持REST HTTP(S) 1.0/1.1 operations (GET,PUT,POST etc) for XML, JSON,etc
- 支持MIME and MTOM 附件
- 支持IPv4,IPv6, TCP 和UDP
- 支持CGI,FastCGI
- 支持嵌入到Apache,IIS中发布
- 自带了一个Web server (multithreaded, SSL, compression)用于发布
- 可适用于WinCE, Palm, Symbian, VxWorks, Andriod, iPhone等小设备
- ...(拣主要的,其余忽略)
二、gSOAP结构
目前gSOAP的版本是2.8.12,作者认为,gSOAP的组织结构以及使用的方便性,在开源项目中是比较好的。
在应用中,我们首先要应用它的两个工具: soapcpp2和 wsdl2h。所幸的是这个两个工具在gSOAP包中已经被编译生成(bin目录下),所以我们只要拿来用即可,gSOAP使用的方便性就体现出来了。另一个方便性是它的源文件个数较少,如果我们不去研究,少的文件个数包含在我们的工程中,也减少了维护的成本。
1.soapcpp2的用法
Soapcpp2是一个根据.h文件生成若干支持webservice的代码生成工具,生成的代码文件包括webservice客户端和服务器的实现框架,XML数据绑定等,具体说明如下:
文件 | 描述 |
soapStub.h | 根据输入的.h文件生成的数据定义文件,一般我们不直接引用它。 |
soapH.h soapC.cpp | 客户端和服务器端应包含该头文件,它包含了soapStub.h。针对soapStub.h中的数据类型,cpp文件实现了序列化、反序列化方法。 |
soapXYZProxy.h soapXYZProxy.cpp | 这两个文件用于客户端,是客户端调用webservice的框架文件,我们的代码主要在此实现或从它继承。 |
soapXYZService.h soapXYZService.cpp | 这两个文件用于服务器端,是服务器端实现webservice的框架文件,我们的代码主要在此实现或从它继承。 |
.xsd | 传输消息的schema,,我们可以看看是否满足我们的协议格式(如果有此要求) |
.wsdl | 这个就不用说了。 |
.xml | 满足webservice定义的例子message,即实际的传输消息,我们可以看看是否满足我们的协议格式(如果有此要求)。 |
.nsmap | 命名空间的定义,对命名空间不敏感的,不用关注。 |
使用soapcpp2时,可选项如下:
选项 | 描述 |
-1 | Soap1.1绑定 |
-2 | SOAP1.2绑定 |
-C | 只生成客户端代码 |
-S | 只生成服务器端代码 |
-T | 生成自动测试代码 |
-L | 不生成 soapClientLib/soapServerLib |
-a | 用 SOAPAction 和WS-Addressing调用服务器端方法 |
-A | 用 SOAPAction 调用服务器端方法 |
-b | 采用char[N]这样的方式来表示string |
-c | 生成的是C代码,不是C++代码 |
-d < path > | 将代码生成在 < path > 下 |
-e | 生成 SOAP RPC 样式的绑定 |
-f N | File split of N XML serializer implementations per file |
-h | 显示一个简要的用法信息 |
-i | 生成的服务代理类和对象从struct soap继承而来 |
-j | 生成的服务代理类和对象包含struct soap而来 (C代码的唯一选择) |
-I < path > | 包含其他文件时使用,指明 < path > (多个的话,用`:'分割),相当于#import ,该路径一般是gSOAP目录下的import目录,该目录下有一堆文件供soapcpp2生成代码时使用。 |
-n | 用于生成支持多个客户端和服务器端(具体内容参考gSOAP文档) |
-p < name > | 生成的文件前缀采用< name > ,而不是缺省的 "soap" |
-q < name > | C++代码中,所有声明的命名空间 |
-s | 生成的代码在反序列化时,严格检查XML的有效性 |
-t | 生成的代码在发送消息时,采用xsi:type方式 |
-u | 在 WSDL/schema 输出文件中不产生XML注释 |
-v | 显示版本信息 |
-w | 不生成 WSDL 和 schema 文件 |
-x | 不生成 XML 形式的传输消息文件 |
-y | 在XML 形式的传输消息文件中,包含 C/C++ 类型信息 |
2. wsdl2h的用法
该工具是可以根据输入的wsdl或XSD或URL,产生相应的C/C++形式的.h(不能直接引用),供soapcpp2使用。
wsdl2h主要的运行选项如下:
选项 | 描述 |
-a | 对匿名类型,产生基于顺序号的结构体名称 |
-c | 生成C代码 |
-f | 对schema扩展,产生flat C++ 类 |
-g | 产生全局的元素声明 |
-h | 显示帮助信息 |
-I path | 包含文件时指明路径,相当于#import |
-j | 不产生 SOAP_ENV__Header 和SOAP_ENV__Detail 定义 |
-k | 不产生 SOAP_ENV__Header mustUnderstand qualifiers |
-l | 在输出中包含license信息 |
-m | 用 xsd.h 模块来引入类型信息 |
-N name | 用name 来指定服务命名空间的前缀。 |
-n name | 用name 作为命名空间的前缀,取代缺省的ns |
-o file | 输出文件名 |
-q name | 所有的声明采用 name 作命名空间 |
-s | 不产生 STL代码 (即不用 std::string,std::vector) |
-t file | 使用自己指定的type map file而不是缺省的typemap.dat |
-u | 不生成 unions |
-v | 产生详细的输出信息 |
-w | always wrap response parameters in a response struct |
-y | 为structs,enums产生 typedef 定义 |
-_ | 不产生 _USCORE (用UNICODE _x005f代替) |
-? | 显示帮助信息 |
三、用gsoap开发web service的大致思路
我们开发webservice应用,大致有两个方向:
1. API接口固定,不关心底层的通讯,将SOAP作为应用层协议
此时,我们先定义接口,编写好.h文件,运行soapcpp2生成出相应的代码,对服务器端,修改XXXService文件,实现业务逻辑,对客户端,修改XXXProxy文件,实现业务逻辑。
2. 通讯协议固定(当然需要基于XML的)或只有wsdl,将SOAP作为“传输层”协议
此时,我们必须根据通讯协议或wsdl生成相应的C/C++类型的.h文件,如果需要我们自己编写wsdl,则需要一点其相关知识,不过我们可以用C#等生成一个简单的wsdl,照猫画虎即可。运用wsdl2h,我们可以生成.h文件,有了.h后,按上面的步骤继续。
(待续,下一节给出实例)