gSOAP 入門


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可以給用戶,即程序員,提供協議透明,通過什么方式呢?通過自動生成的代碼)
 
     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語言代碼)

     盡管gSOAP為不同平台准備了二進制格式的工具,但他們生成的代碼是等價的。這意味着生成的源代碼可以移植到其他平台並進行本地化編譯。

     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 快速開始:開發一個Web Service客戶端應用程序

 通過高級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 
(注:在瀏覽器中訪問 http://www.genivia.com/calc.wsdl 可以獲得一個wsdl文件,在該命令行中,用此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++的存根。為了生成它,我們使用soapcpp2編譯器:

soapcpp2 -i -C -Iimport calc.h

  選項-i指示我們希望得到C++代理和包含客戶端(服務端)代碼的對象。-C指示只生成客戶端對象(默認情況下,gsoapcpp2同時生成客戶端和服務端對象)。選項-I指示需要從import目錄引入stl vector.h文件,以支持STL容器序列化,import目錄也在gSOAP包中。

 假定我們開發一個C++計算器客戶端:

wsdl2h -o calc.h http://www.genivia.com/calc.wsdl 
soapcpp2 -i -C calc.h

(注:事實上執行第二行命令需要指定-I路徑,如下所示:其中紅色的文件是該步驟生成的) 

./soapcpp2 -i -C -I/home/infor/renhc/gsoap/gsoap_2.8.5/gsoap-2.8/gsoap/import calc.h

[infor@s123 linux386]$ ls -ltr
total 3376
-rwxr-xr-x  1 infor app 2383149 Dec  6 11:46 wsdl2h
-rwxr-xr-x  1 infor app  818123 Dec  6 11:46 soapcpp2
-rw-r--r--  1 infor app    5249 Dec  6 13:53 calc.wsdl
-rw-r--r--  1 infor app   24316 Dec  6 14:42 calc.h-rw-r--r--  1 infor app    7101 Dec  6 14:44 soapStub.h
-rw-r--r-- 1 infor app 34463 Dec 6 14:44 soapH.h -rw-r--r-- 1 infor app 95689 Dec 6 14:44 soapC.cpp -rw-r--r-- 1 infor app 3573 Dec 6 14:44 soapcalcProxy.h -rw-r--r-- 1 infor app 12319 Dec 6 14:44 soapcalcProxy.cpp -rw-r--r-- 1 infor app 490 Dec 6 14:44 calc.sub.res.xml -rw-r--r-- 1 infor app 478 Dec 6 14:44 calc.sub.req.xml -rw-r--r-- 1 infor app 490 Dec 6 14:44 calc.pow.res.xml -rw-r--r-- 1 infor app 478 Dec 6 14:44 calc.pow.req.xml -rw-r--r-- 1 infor app 521 Dec 6 14:44 calc.nsmap -rw-r--r-- 1 infor app 490 Dec 6 14:44 calc.mul.res.xml -rw-r--r-- 1 infor app 478 Dec 6 14:44 calc.mul.req.xml -rw-r--r-- 1 infor app 490 Dec 6 14:44 calc.div.res.xml -rw-r--r-- 1 infor app 478 Dec 6 14:44 calc.div.req.xml -rw-r--r-- 1 infor app 490 Dec 6 14:44 calc.add.res.xml -rw-r--r-- 1 infor app 478 Dec 6 14:44 calc.add.req.xml

 我們使用生成的soapcalcProxy類和XML命名空間映射表calc.nsmap來訪問Web服務。該soapcalcProxy類是調用服務的一個代理。

#include "soapcalcProxy.h" 
#include "calc.nsmap" 
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); 
}

 

    接下來我們編譯並鏈接生成的soapC.cpp和soapcalcProxy.cpp,以及動態鏈接庫-lgsoap++(如果你沒有安裝該庫,可以將stdsoap2.cpp引入到你的代碼)。(注:上面就構建完了基於C++的客戶端)

 

1.3 快速開始:開發Web 服務

開發服務端程序也很簡單。這里我們使用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”指令綁定到 urn:currentTime命名空間。 //gsoap指令用來設置服務屬性,在本例中有 name、 namespace和 location。
 
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
為了激活這個服務,將生成的 currentTime.cgi二進制程序拷貝到bin-cgi目錄下,並賦以恰當的權限。
 
soapcpp2工具生成WSDL描述文件currentTime.wsdl。你可以使用這個WSDL發布你的服務。你不需要使用這個WSDL去開發客戶端。因為你已經有了 currentTime.h,使用soapcpp2的-C選項可以生成客戶端代碼。(注:參考1.2節)

 CGI可以方便的通過標准I/O交換信息。因此,我們使用自動生成的請求樣例代碼來測試:

./currentTime.cgi < currentTime.currentTime.req.xml

這樣,得到的返回也是SOAP XML。

另外還有一個更優雅的C++服務端實現:使用soapcpp2的-i(或-j)選項生成C++的客戶端和服務端的服務類,使用這個類同時可以構建客戶端也可以構建服務端。使用這個選項就不需要 soapClient.cpp和 soapServer.cpp了,因為我們有了客戶端和服務端的類實現:

soapcpp2 -i -S currentTime.h
這樣就會生成 soapcurrentTimeService.h和 soapcurrentTimeService.cpp文件,以及輔助文件 soapStub.h和 currentTime.nsmap。
 
使用 currentTimeService對象,我們重寫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; 
   return server.serve(); 
} 
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端口上以迭代方式運行服務,可以使用:

return currentTimeService.run(8080);

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM