1
gSOAP工具基於編譯器技術為C/C++提供自動的SOAP和XML數據綁定. 該工具使用自動生成代碼以及先進的映射方法,簡化了基於C/C++的SOAP/XML Web service和XML應用程序的開發。。大多數Web services工具采用以WSDL/SOAP為中心的觀點,並且提供一組API,使用這些API必須使用相應的類庫來處理特定XML數據結構。這強迫用 戶去適應該程序邏輯才能使用這些類庫,因為用戶在使用該特定廠商的API時必須編寫代碼去填充XML和抽取XML數據。這往往導致一個脆弱的解決方案,幾 乎沒有數據一致性、類型安全和XML驗證的保證。與其他工具不同的是,gSOAP使用編譯器技術為用戶隱藏了 WSDL、SOAP、特定XML的實現細節,同時自動提供XML有效性驗證、內存管理和類型安全序列化,從而提供透明的解決方案。gSOAP工具可將原有 的數據類型和用戶自定義的數據類型映射成等價的XML數據類型,反之亦然。因此,通過一個簡單的API得到了完美的SOAP互操作性,從而可使用用戶從 WSDL/SOAP/XML的細節中解脫出來,集中精力處理應用程序邏輯。 gSOAP工具支持傳統的C/C++代碼(以及留有C接口的其他編程語言)、嵌入式系統、那些和其他SOAP程序共享計算資源和信息的實時SOAP/XML應用程序之間的集成,可以跨平台,適用不同的語言環境和穿透防火牆。 gSOAP工具常常使用C/C++實現XML數據綁定。這意味著程序本地數據結構可被自動地用XML編碼,而不需要額外去編寫轉換代碼。該工具還為了XML數據綁定生成XML模式,所以外部程序可以基於該模式使用XML數據。
1.1 快速入門
使用gSOAP工具構建Web services應用程序或實現自動化XML數據綁定,你需要具備如下條件:
- 從http://www.genivia.com/Products/downloads.html下載gSOAP軟件包。(選擇標准版)
- 一個C或者C++的編譯器.
- 如想支持SSL(HTTPS)和壓縮,你還需要安裝OpenSSL、Zlib庫.這些庫適用於大多數平台,同時通常也是已經安裝好的.
gSOAP是獨立的軟件,不需要安裝第三方軟件(除非你想使用OpenSSL或者你想重新構建soapcpp2工具,見下文). 從SourceForge獲取的gSOAP包在gsoap/bin目錄下有預構建的工具:(注:SourceForget是開源軟件開發者進行開發管理的集中式場所,也是全球最大開源軟件開發平台和倉庫):
- wsdl2h :WSDL/模式導入和數據映射綁定工具。(注:該工具將wsdl轉換為開發用的.h文件).
- soapcpp2 :存根/框架編譯器和代碼生成器。(注:該工具依據.h文件自動生成部分C/CPP語言代碼).
這兩個程序支持Windows、Linux和Mac OS 平台,詳情參考README文件。.盡管gSOAP為不同平台准備了二進制格式的工具,但他們生成的代碼是等價的。這意味著生成的源代碼可以移植到其他平台並進行本地化編譯. 如果你沒有該工具或者你想重新構建,你需要:
- 一個C編譯器和Bison(或Yacc)來構建soapcpp2。(注Bison和Yacc也是一種編譯器)
- 一個C編譯器和Flex(或Lex)來構建soapcpp2。
- 一個C++編譯器來構建wsdl2h。
Bison和Flex是首選的。兩者與gSOAP基於相同的開源標准發布的。
- ison 可從此處獲得: http://www.gnu.org/software/bison
- Flex 可從此處獲得: http://flex.sourceforge.net
gSOAP引擎可以被構建成libgsoap.a和libgsoap++.a庫,後者支持SSL。參照README.txt的指示可以看到如何通過 gSOAP包裡的autoconf和automake構建與平台無關的庫。或者,你將引擎的源代碼stdsoap2.c(或stdsoap2.cpp)直 接編譯並鏈接進你們工程裡。(注:說明gSOAP提供兩種使用方式 ,一種編譯成動態鏈接庫,或者直接將源代碼編譯進工程)gSOAP包中,在samples目錄下有很多例子。執行make命令可以構建這些例子程序。這些例子同時也是用來展示gSOAP不同特性的。比如,在 samples/mtom-streaming中,一個流式的MTOM附件服務端和客戶端程序展示高效的文件傳輸;在samples /webservice中,SSL-secure網絡服務端展示可以為Web流覽器和Web服務調用生成不同的內容。諸如此類,還有很多。
1.2
通過高級XML模式分析器和代碼生成器可實現XML數據綁定,這大大減少了構建Web Service程序的難度。wsdl2h工具導入一個或多個WSDL和XML模式可以生成C/C++頭文件,該文件定義了Web Service操作以及C/C++數據類型。gsoapcpp2然手根據該頭文件生成XML序列化的數據類型、客戶端框架代碼 (soapClient.cpp)和服務端框架代碼(soapServer.cpp)。gSOAP編譯器也可以生成WSDL定義文件,用來從頭實現一個服務。這個閉環可以使Web services開發基於WSDL文件或者基於C/C++頭文件中的一系列選項,不需要用戶去分析Web服務細節。你只需要遵循一些步驟執行命令行或Makefile(使用MSVC++ IDE的話參照sample目錄下的MSVC++例子)。例如,為了生成計算器Web應用代碼,我們通過命令行執行wsdl2h工具,從URL上的 WSDL文件生成頭文件,這裡使用-o指定輸出文件名:
> wsdl2h -o calc.h http://www.genivia.com/calc.wsdl
這樣就生成了描述服務操作定義及數據類型定義的頭文件calc.h。接著可以通過soapcpp2將該頭文件生成框架代碼或XML序列化例程。 calc.h頭文件包含所有的說明,你可以使用Doxygen(http://www.doxygen.org)來生成開發文檔。用wsdl2h生成的服務定義頭文件同樣包含如何調用服務的信息。在這個例子中,我們開發一個基於C++的計算器服務。默認情況下,gSOAP假定我們使用C++的STL。如不想使用STL,使用選項-s:
> wsdl2h -s -o calc.h http://www.genivia.com/calc.wsdl
構建純C程序,使用-c:
> wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl
到現在為止,我們還沒有生成C/C++的存根。為了生成它,我們使用soapcpp2編譯器:
> soapcpp2 -i -C -Iimport calc.h
選項-i指示我們希望得到C++代理和包含客戶端(服務端)代碼的對象。-C指示只生成客戶端對象(默認情況下,gsoapcpp2同時生成客戶端和服務 端對象)。選項-I指示需要從import目錄引入stlvector.h文件,以支持STL容器序列化,import目錄也在gSOAP包中。假定我們開發一個C++計算器客戶端,我們使用生成的soapcalcProxy類和XML命名空間映射表calc.nsmap來訪問Web服務。該soapcalcProxy類是調用服務的一個代理。:
#include "soapcalcProxy.h"
#include "calc.nsmap"
int main()
{
calcProxy service;
double result;
if (service.add(1.0, 2.0, result) == SOAP_OK)
std::cout << "The sum of 1.0 and 2.0 is " << result << std::endl;
else
service.soap_stream_fault(std::cerr);
service.destroy(); // 刪除數據釋放內存
}
接下來我們編譯並鏈接生成的soapC.cpp和soapcalcProxy.cpp,以及動態鏈接庫-lgsoap++(如果你沒有安裝該庫,可以將stdsoap2.cpp引入到你的代碼)。(注:上面就構建完了基於C++的客戶端).假定我們開發的是C語言客戶端,那麼我們可以這樣: wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl and soapcpp2 -C calc.h。 這種情況下,我們的代碼使用一個簡單的C函數調用服務,我們還需要顯式使用soap_end,soap_free刪除數據和上下文
#include "soapH.h"
#include "calc.nsmap"
int main()
{
struct soap *soap = soap_new();
double result;
if (soap_call_ns__add(soap, 1.0, 2.0, &result) == SOAP_OK)
printf("The sum of 1.0 and 2.0 is %lg\n", result);
else
soap_print_fault(soap, stderr);
soap_end(soap);
soap_free(soap);
}
這個計算器的例子是相當簡單,此處只用來說明開發過程。這與大型程序開發流程是相似的。更多的可以參考sample目錄下的例子。
1.3
開發服務端程序也很簡單。這裡我們使用CGI,因為這是個簡單的機制。(注:CGI英文全拼是Common Gateway Interface,即通用網關接口)。這不是首選的部署機制,因為CGI非常慢而且無國籍,我們建議開發獨立的gSOAP HTTP/HTTPS服務(參照本節最後部分注解)或者使用Apache組件,再或者IIS(在gSOAP包的gsoap/mod_gsoap目錄下)。假設我們開發一個基於CGI的服務,該服務返回GMT時間。CGI可以非常簡單的將服務發布到Web站點。我們以一個gSOAP頭文件開始本例,currentTime.h包含服務的定義。如果我們能得到WSDL文件,我們可以使用wsdl2h得到這樣的頭文件。如果沒有WSDL,你可以使用C/C++重頭定義一個頭文件,然後使用gSOAP工具生成源代碼和WSDL。我們的currentTime服務只有一個輸出參數,就是當前時間,在currentTime.h文件中定義如下:
// File: currentTime.h
//gsoap ns service name: currentTime
//gsoap ns service namespace: urn:currentTime
//gsoap ns service location: http://www.yourdomain.com/currentTime.cgi
int ns__currentTime(time_t& response);
注意,我們關聯一個XML命名空間前綴“ns”和命名空間urn:currentTime到WSDL服務和SOAP/XML信息。gSOAP工具使用特殊 轉化方式得到標識符名字:命名空間前綴後跟兩個下劃線。之所以如此處理命名空間,是為了避免命名沖突。命名空間前綴“ns”通過“//gsoap”指令綁 定到 命名空間。 指令用來設置服務屬性,在本例中有 、 和 。CGI的服務實現需要在soap上下文上調用soap_serve,soap環境通過soap_new創建。服務的具體實現就像一個函數,該函數由RPC調度器使用soap_servey調用:
// File: currentTime.cpp
#include "soapH.h" // include the generated declarations
#include "currentTime.nsmap" // include the XML namespace mappings
int main()
{
// create soap context and serve one CGI-based request:
return soap_serve(soap_new());
}
int ns__currentTime(struct soap *soap, time_t& response)
{
response = time(0);
return SOAP_OK;
}
注意,我們傳遞帶有soap上下文信息的soap結構給服務例程。這非常方便於確定連接的性能,還可以使用soap_malloc(soap, num_bytes)動態申請空間,以及在服務結束時動態刪除他們。我們運行soapcpp2編譯器,生成服務端代碼:
> soapcpp2 -S currentTime.h
接著編譯得到CGI二進制程序:
> c++ -o currentTime.cgi currentTime.cpp soapC.cpp soapServer.cpp stdsoap2.cpp
可以在gsoap目錄下找到。或者,如果你安裝了gsoap,你可以選擇鏈接libgsoap++庫,就不用使用 源碼了,像這樣:
> c++ -o currentTime.cgi currentTime.cpp soapC.cpp soapServer.cpp -lgsoap++
為了激活這個服務,將生成的 二進制程序拷貝到bin-cgi目錄下,並賦以恰當的權限。soapcpp2工具生成WSDL描述文件currentTime.wsdl。你可以使用這個WSDL發布你的服務。你不需要使用這個WSDL去開發客戶端。因為你已經有了 ,使用soapcpp2的-C選項可以生成客戶端代碼。(注:參考1.2節)CGI可以方便的通過標准I/O交換信息。因此,我們使用自動生成的請求樣例代碼來測試:
> ./currentTime.cgi < currentTime.currentTime.req.xml
這樣,得到的返回也是SOAP XML. 面的過程同樣適用於純C語言。只需要在soapcpp2的-S選項後添加-c選項就可以生成ANSI C代碼。當然,在C語言中我們使用指針而不是引用,同時 文件也必須只能使用C類型。另外還有一個更優雅的C++服務端實現:使用soapcpp2的-i(或-j)選項生成C++的客戶端和服務端的服務類,使用這個類同時可以構建客戶端也可以構建服務端。使用這個選項就不需要 和 了,因為我們有了客戶端和服務端的類實現:
> soapcpp2 -i -S currentTime.h
這樣就會生成 和 文件,以及輔助文件 和 。使用 對象,我們重寫CGI服務:
// File: currentTime.cpp
#include "soapcurrentTimeService.h" // include the proxy declarations
#include "currentTime.nsmap" // include the XML namespace mappings
int main()
{
// create server and serve one CGI-based request:
currentTimeService server;
server.serve();
server.destroy();
}
int currentTimeService::currentTime(time_t& response)
{
response = time(0);
return SOAP_OK;
}
編譯
> c++ -o currentTime.cgi currentTime.cpp soapC.cpp soapcurrentTimeService.cpp -lgsoap++
接著安裝CGI二進制文件。安裝方法請查閱Web服務文檔。如果想在8080端口上以迭代方式運行服務,可以使用:
while (server.run(8080) != SOAP_TCP_ERROR)
server.soap_stream_fault(std::cerr);
想實現線程服務,請查看7.2.4節。該節講述了通過多個線程來處理多個SO來請求。線程池也可以使用。7.2.7節有更多的服務端類的描述。7.1.4節有更多的客戶端代理類的描述.
1.4
換句換說, C / C++ 自動讀取和編寫XML數據如何映射到schemas(XSD文件。 gsoap 提供自動化的綁定機制可以將C/C++的數據綁定到XML裡,任何C/C++的數據類型都可以. 一個XML模式(XSD文件)可轉化為一組C或C ++的定義
,比DOM或者SAX 解析方式更容易讓你的程序使用. 從本質上來說, XML架構中的每個XML組件都對應著一個C / C++數據類型. 使用XSD來對class 進行映射優點顯而易見:
XSD
C++
<complexType name="Address">
class ns__Address
<sequence>
{
<element name="name" type="string"/>
std::string name;
<element name="home" type="tns:Location" minOccurs="0"/>
ns__Location *home;
<element name="phone" type="unsignedLong"/>
ULONG64 phone;
<element name="dob" type="dateTime"/>
time_t dob;
</sequence>
<attribute name="ID" type="int" use="required"/>
@
int ID;
</complexType>
}
通過這種方式, 不需要DOM遍歷和SAX事件就能自動的在符合XML 架構的XML元素到類的成員的創建. 此外, C/C++ 數據綁定XML的操作是安全的. 類型安全就是是說 C/C++ 確保只有有效的XML文檔可以解析和生成。 wsdl2h工具自動執行WSDL和XML模型的映射到C/C++. wsdl2h 輸出 The output of wsdl2h
is an annotated header file that includes comments and documentation on
the use of the C/C++ declarations in a SOAP/XML client/server or in a
generic application for reading and writing XML using the auto-generated
serializers.
We will illustrate this further with an example. Suppose we have an XML document with a book record:
<book isbn="1234567890">
<title>Farewell John Doe</title>
<publisher>ABC's is our Name</publisher>
</book>
可以用XML 來表示一個書本的元素和類型
<schema ...>
<element name="book">
<complexType>
<sequence>
<element name="title" type="string" minOccurs="1"/>
<element name="publisher" type="string" minOccurs="1"/>
</sequence>
<attribute name="isbn" type="unsignedLong" use="required"/>
</complexType>
</element>
</schema>
使用 wsdl2h 轉換 XML schema 定義book 類型 到一個類,如下:
class book
{
@ULONG64 isbn;
std::string title;
std::string publisher;
}
請注意上面的例子,是使用@來表示元素的屬性的. 這些特殊的gSOAP注釋是soapcpp2 工具生成的,用於對數據序列化讀取和編寫XML . soapcpp2 工具生成所有必要的代碼來解析和生成XML的書對象. 驗證如 minOccurs="1" 和 use="required"是否包含在生成的代碼裡. 用XML表示一本書, 我們首先創建一個SOAP(engine context ),並用它與soap_write_book(由soapcpp2生成的)使用標准輸出寫XML中的對象:
soap *ctx = soap_new1(SOAP_XML_INDENT); // new context with option
book bk;
bk.isbn = 1234567890;
bk.title = "Farewell John Doe";
bk.publisher = "ABC's is our Name";
if (soap_write_book(ctx, &bk) != SOAP_OK)
... error ...
soap_destroy(ctx); // clean up allocated class instances
soap_end(ctx); // clean up allocated temporaries
soap_free(ctx); // delete context
ctx gSOAP 上下文引擎 (soap 結構類型) 用於控制設置和狀態保持的。 例如XML的格式化, (e.g. SOAP_XML_INDENT), 設置序列化選項, 獲取當前狀態,設置I/O. 只需要簡單的設置輸出流 (std::ostream) ctx->os 就能將上下文重定向到string 或文件裡.此外,當序列化一個圖表,在代碼調用soap_put方法以確保輸出符合對象圖的SOAP編碼(你也可以使用一個基於id-ref的編碼)之前,先在對象或類型上調用串行器bk.soap_serialize(ctx)。細節見7.5節,解析典型的xml成為一本書對象用:
soap *ctx = soap_new1(SOAP_XML_STRICT); // new context with option
book bk;
if (soap_read_book(ctx, &bk) != SOAP_OK)
... error ...
else
cout << bk.isbn << ", " << bk.title << ", " << bk.publisher << endl;
... further use of bk ...
soap_destroy(ctx); // delete deserialized objects
soap_end(ctx); // delete temporaries
soap_free(ctx); // delete context
Automatic built-in XML validation (enabled with SOAP_XML_STRICT)
ensures that data members are present so we can safely print them in this
example, thus ensuring consistency of data with the XML schema. Set the
ctx->is input stream to read from a file/string stream
instead of stdin.
The soap_destroy and soap_end calls deallocate the deserialized
content, so use with care. In general, memory management is automatic in gSOAP
to avoid leaks.
The above uses a very simple example schema. The gSOAP toolkit handles
all XML schema constructs defined by the XML schema standard. The
toolkit is also able to (de)serialize pointer-based C/C++
data structures (including cyclic graphs), structs/classes, unions,
enums, STL
containers, and even special data types such as struct tm. Therefore, the toolkit works in two directions: from WSDL/schema to C/C++ and from C/C++ to WSDL/schema.
The gSOAP toolkit also handles multiple schemas defined in multiple
namespaces. Normally the namespace prefixes of XML namespaces are added
to the C/C++ type
definitions to ensure type uniqueness. For example, if we would combine
two
schemas in the same application where both schemas define a book object,
we need to resolve this conflict. In gSOAP this is done using namespace
prefixes, rather than C++ namespaces (research has pointed out that XML
namespaces are not equivalent to C++ namespaces). Thus, the book class
might actually be bound to an XML namespace and the class would be named
ns__book, where ns is bound to the corresponding namespace.
The following options are available to control serialization:
soap->encodingStyle = NULL; // to remove SOAP 1.1/1.2 encodingStyle
soap_mode(soap, SOAP_XML_TREE); // XML without id-ref (no cycles!)
soap_mode(soap, SOAP_XML_GRAPH); // XML with id-ref (including cycles)
soap_set_namespaces(soap, struct Namespace *nsmap); //to set xmlns bindings
其他可用於XML 綁定的表示, 可以看 9.12 章節.
獲得更多的XML綁定C/C++ 幫助,看 7.5章節.
1.5
gSOAP的亮點:
- 獨特的互操作性功能: 工具生成類型的安全SOAP 編組程序(反序列化本地和用戶定義的C和C+ +數據結構).
-
gSOAP支持WSDL 1.1, SOAP 1.1, SOAP 1.2, SOAP RPC 編碼方式以及 literal/document 方式.
gSOAP is one of the few SOAP toolkits that support the full range of SOAP 1.1
RPC encoding features including sparse multi-dimensional arrays and polymorphic
types. For example, a service operation with a base class parameter may accept
derived class instances from a client. Derived class instances keep their
identity through dynamic binding. The toolkit also supports all XSD
schema type constructs and has been tested against the W3C XML Schema Patterns
for Databinding Interoperability working group and of gSOAP release 2.8.x
passes all tests.
-
Supports WS-Security, WS-Addressing, WS-ReliableMessaging, C14N exclusive
canonicalization. The protocols are implemented using code generation with
wsdl2h and soapcpp2. The gSOAP tools can be used to generate messaging
protocols for other WS-* protocols.
-
gSOAP supports XML-RPC and RSS protocols. Examples are provided.
- JSON support is included in the XML-RPC library to switch between XML-RPC
and JSON protocols. For more details, see the samples/xml-rpc-json folder in the package.
-
The wsdl2h tool supports WS-Policy. Policy assertions are included in
the generated service description header file with recommendations and usage
hints.
-
gSOAP supports MIME (SwA), DIME, and MTOM attachments and has streaming
capabilities to direct the data stream to/from resources.
gSOAP is the only toolkit that supports streaming MIME, DIME, and MTOM
attachment transfers, which allows you to exchange binary data of practically
unlimited size in the fastest possible way (streaming) while ensuring the
usefulness of XML interoperability.
-
gSOAP 支持 SOAP-over-UDP
-
gSOAP 支持IPv4 and IPv6.
-
gSOAP 支持Zlib deflate and gzip compression (for HTTP, TCP/IP, and XML file storage).
-
gSOAP 支持 SSL (HTTPS) 使用 OpenSSL.
-
gSOAP 支持 HTTP/1.0, HTTP/1.1 keep-alive, chunking, basic authentication, and digest authentication using a plugin.
-
gSOAP 支持SOAP one-way messaging.
-
The schema-specific XML pull parser is fast and efficient and does not require intermediate data storage for
demarshalling to save space and time.
-
The soapcpp2 compiler includes a WSDL and schema generator for convenient
Web Service publishing.
-
The soapcpp2 compiler generates sample input and output messages
for verification and testing (before writing any code). An option (-T)
can be used to automatically implement echo message services for testing.
-
The WSDL importer wsld2h (converts to gSOAP header files) for automated client and server development.
-
Generates source code for stand-alone Web Services and client applications.
-
Ideal for small devices such as Palm OS, Symbian, Pocket PC, because the memory footprint is small.
-
Ideal for building web services that are compute-intensive and are therefore best written in C and C++.
-
Platform independent: Windows, Unix, Linux, Mac OS X, Pocket PC, Palm OS, Symbian, VXWorks, etc.
-
Supports serializing of application's native C and C++ data structures,
which allows you to save and load XML serialized data structures to and
from files.
-
Selective input and output buffering is used to increase efficiency, but full message buffering to determine HTTP message length
is not used. Instead, a three-phase serialization method is used to determine message length. As a result, large data sets
such as base64-encoded images can be transmitted with or without DIME attachments by small-memory devices such as PDAs.
-
Supports C++ single class inheritance, dynamic binding, overloading, arbitrary pointer structures such as lists, trees, graphs,
cyclic graphs, fixed-size arrays, (multi-dimensional) dynamic arrays, enumerations, built-in XSD Schema types including
base64Binary encoding, and hexBinary encoding.
-
No need to rewrite existing C/C++ applications for Web service deployment. However, parts of an application that use unions,
pointers to sequences of elements in memory, and void* need to be modified, but only if the data structures that
adopt them are required to be serialized or deserialized as part of a service operation invocation.
-
Three-phase marshalling: 1) analysis of pointers, single-reference, multi-reference, and cyclic data structures, 2) HTTP
message-length determination, and 3) serialization as per SOAP 1.1 encoding style or user-defined encoding styles.
-
Two-phase demarshalling: 1) SOAP parsing and decoding, which involves the reconstruction of multi-reference and cyclic data
structures from the payload, and 2) resolution of "forward" pointers (i.e. resolution of the forward href attributes in SOAP).
-
Full and customizable SOAP Fault processing (client receive and service send).
-
Customizable SOAP Header processing (send and receive), which for example enables easy transaction processing for the service to
keep state information.