級別: 中級
Karthik Subbian (ksubbian@in.ibm.com), 高級軟件工程師, IBM India
Ramakrishnan Kannan (rkrishnan@in.ibm.com), 高級軟件工程師, IBM India
2006 年 9 月 18 日
XML-RPC 是一個簡單而強(qiáng)大的輕量級消息傳遞協(xié)議,可支持基于 XML 的跨異類平臺的通信。在本文中,您將了解如何為 C++ 程序構(gòu)建基于 XML-RPC 的服務(wù)。
引言
Internet 現(xiàn)在的受歡迎程度越來越高,由于這個原因及其固有的優(yōu)勢,促使開發(fā)人員和 IT 部門開始著手將復(fù)雜的 C/C++ 業(yè)務(wù)和科學(xué)應(yīng)用程序向基于 Web 的環(huán)境遷移。簡單對象訪問協(xié)議(Simple Object Access Protocol,SOAP)、代表性狀態(tài)傳輸(Representational State Transfer,REST)以及 XML 遠(yuǎn)程過程調(diào)用協(xié)議(XML Remote Procedure Call,XML-RPC)等 Web 服務(wù)協(xié)議可幫助將此類遺留應(yīng)用程序集成到萬維網(wǎng),例如,可以使用 XML-RPC 作為將現(xiàn)有 C/C++ 程序與其他客戶端技術(shù)集成的機(jī)制。這篇文章將幫助您確定何時選擇 XML-RPC 而不使用 SOAP 與 REST。另外,本文還提供了詳細(xì)步驟指南以及使用開放源代碼 XML-RPC 庫的 C++ 集成示例代碼片段。
為什么選擇 XML-RPC?
集成 C/C++ 的挑戰(zhàn)可以通過多種方式加以解決。C/C++ 代碼集成的典型方法包括通過公共對象請求代理體系結(jié)構(gòu)(Common Object Request Broker Architecture,CORBA)、分布式組件對象模型(Distributed Component Object Model,DCOM)、遠(yuǎn)程方法調(diào)用(Remote Method Invocation,RMI)Internet ORB互聯(lián)協(xié)議(Internet Inter-ORB Protocol,IIOP)以及 Java? 本機(jī)接口(Java? Native Interface,JNI)等進(jìn)行集成。
圖 1 顯示了利用現(xiàn)有 C++ 代碼集成(使用上面提到的典型方法)的采用不同編程語言(Java、VC++、PL/1)開發(fā)的三個不同應(yīng)用程序。
圖 1. 沒有 XML-RPC 的當(dāng)前方案

正如您看到的,C++ 代碼應(yīng)為每個 RMI/IIOP/JNI、CORBA 和 DCOM 客戶端集成技術(shù)公開相應(yīng)的接口。這就要求進(jìn)行三次開發(fā)工作,顯然會使部署和管理此類復(fù)雜接口的過程變得更為困難和麻煩。
在這些情況下,XML-RPC 是一個更好的選擇,因為它可能幫助簡化開發(fā)、部署和管理工作。
圖 2. 使用 XML-RPC

圖 2 顯示了如何使用 XML over HTTP 通過遠(yuǎn)程過程調(diào)用來調(diào)用 C++ 程序。SOAP 和 REST 等備選技術(shù)也能用于相同的目的。不過,您將在下一部分中了解到,這些技術(shù)之間存在一些關(guān)鍵區(qū)別。
SOAP、XML-RPC 及 REST 間的對比
盡管這三個協(xié)議都支持 XML-RPC over HTTP,但就 C++ 而言,它們彼此之間是有區(qū)別的。表 1 提供了這些協(xié)議的各個元素間詳細(xì)的比較。
表 1. SOAP、XML-RPC 及 REST 間的對比
| SOAP | XML-RPC | REST |
定義 | SOAP 是用于在分散的分布式環(huán)境中進(jìn)行信息交換的輕量級協(xié)議。該協(xié)議基于 XML,包括三個部分:信封、一組編碼規(guī)則以及用于表示遠(yuǎn)程過程調(diào)用和響應(yīng)的約定。 | 這是使用 HTTP 作為傳輸協(xié)議和使用 XML 作為編碼方式的遠(yuǎn)程過程調(diào)用。XML-RPC 的設(shè)計力求簡單,并同時允許傳輸、處理和返回復(fù)雜數(shù)據(jù)結(jié)構(gòu)。 | 代表性狀態(tài)傳輸旨在反映設(shè)計良好的 Web 應(yīng)用程序的行為圖像:由網(wǎng)頁組成的網(wǎng)絡(luò),其中用戶通過選擇鏈接繼續(xù)進(jìn)行使用,選擇鏈接將導(dǎo)致將下一頁傳輸給用戶并進(jìn)行呈現(xiàn),以供其使用。 |
目標(biāo) | SOAP 可實現(xiàn)用戶定義的數(shù)據(jù)類型,提供指定接收者的功能、消息特定的處理控制以及其他功能,從而對 XML-RPC 進(jìn)行了擴(kuò)展。 | 非常簡單且條理清楚的可擴(kuò)展格式。HTML 編碼人員應(yīng)該能夠查看包含 XML-RPC 過程調(diào)用的文件,理解其進(jìn)行的工作,并能夠?qū)ζ溥M(jìn)行修改,只需一兩次嘗試就能使其正常工作。此協(xié)議非常容易實現(xiàn),可以快速對其進(jìn)行調(diào)整,以在其他環(huán)境或其他操作系統(tǒng)上運(yùn)行。 | 創(chuàng)建 REST 的目的是為了提供有關(guān) Web 應(yīng)該如何運(yùn)行的設(shè)計模式,并作為 Web 標(biāo)準(zhǔn)和設(shè)計 Web 服務(wù)的指導(dǎo)框架。 |
支持的數(shù)據(jù)類型 | 整數(shù)、Boolean、ASCII 字符串、雙精度帶符號浮點數(shù)、日期時間、結(jié)構(gòu)、數(shù)組、字節(jié)數(shù)組、枚舉、用戶定義數(shù)據(jù)類型、多態(tài)訪問器 | 整數(shù)、Boolean、ASCII 字符串、雙精度帶符號浮點數(shù)、日期時間、結(jié)構(gòu)、數(shù)組。 | 特定于實現(xiàn)。通常支持的類型有整數(shù)、Boolean、ASCII 字符串、雙精度帶符號浮點數(shù)、日期時間、集合、列表、屬性。 |
簡單性 | 比 XML-RPC 略微復(fù)雜 | 易于理解和進(jìn)行開發(fā) | 特定于實現(xiàn) |
穩(wěn)定性 | W3C 接受的標(biāo)準(zhǔn) | 不是標(biāo)準(zhǔn) | 體系結(jié)構(gòu)參考。不需要標(biāo)準(zhǔn) |
互操作性 | 無法與 REST/XML-RPC 互操作 | 無法與 REST/SOAP 互操作 | 無法與 SOAP/XML-RPC 互操作 |
工具 | 很多主要公司(包括 IBM 和 Microsoft)均已開始在其工具中支持 SOAP。 | 工具仍在開發(fā)中。 | 并沒有很多工具支持。 |
自定義能力 | 高度可自定義,不受數(shù)據(jù)類型和協(xié)議限制 | 輕量級,只能在 HTTP 上工作,具有有限的數(shù)據(jù)類型支持 | 只能在 HTTP 上工作 |
庫 | 有很多開放源代碼庫可用。 | 有很多開放源代碼庫可用。將在下面的部分進(jìn)行說明 | 并沒有很多實現(xiàn)庫可用 |
表 2. C++ 的各種 XML-RPC 實現(xiàn)
庫和包名稱 | 說明 |
PDEL | Packet Design Embedded Library 是一個 C 庫,其中通過 http_xml_send_xmlrpc 和 http_servlet_xmlrpc 方法包含了客戶機(jī)和服務(wù)器的 XML-RPC 實現(xiàn)。這些函數(shù)將幫助通過 HTTP 傳輸協(xié)議發(fā)送自定義 XML 數(shù)據(jù)。這個包還包含很多 XML-RPC 之外的其他功能。 |
XMLRPC++ | 這是 XML-RPC 的 C++ 實現(xiàn)。其中提供了簡單的服務(wù)器和客戶機(jī)。通過使用面向?qū)ο蟮募夹g(shù),我們可以集成這些服務(wù)器和客戶機(jī)類,并實現(xiàn)我們自己的 XML-RPC 服務(wù)器,以將業(yè)務(wù)功能作為服務(wù)公開。在本文中,我們的示例實現(xiàn)及相關(guān)示例將使用這個庫。 |
XMLRPC-C | 這是一個 C 實現(xiàn),可供 C 和 C++ 應(yīng)用程序用于將這些方法作為服務(wù)公開。此包中包括一個 abyss Web 服務(wù)器。為了公開 C++ 方法,我們可以為所需的 C++ 方法編寫 C 樣式的包裝,然后使用此庫公開此方法。 |
安裝 XML-RPC++ 庫
為 C++ 程序啟用 XML-RPC 的第一步是下載并安裝 XML-RPC 庫實現(xiàn)。為 C++ 程序提供了各種實現(xiàn)。可以在參考資料部分獲得一個指向更多實現(xiàn)的鏈接。
我們的示例程序?qū)⑹褂?span lang="EN-US"> XMPLRPC++ 實現(xiàn)。有關(guān)將此實現(xiàn)下載并安裝到 Linux、AIX、32 位 Windows 平臺以及其他類似平臺的詳細(xì)信息,請參閱參考資料部分。我們的示例實現(xiàn)將基于 Red Hat 9 平臺,使用的是 XML-RPC++ 0.7 庫。
示例 C++ 應(yīng)用程序
此處的示例應(yīng)用程序是一個簡單的兩個整數(shù)相加的操作,將使用名為“operations”的用戶定義類。清單 1 顯示了 operations 類的代碼片段。
清單 1. Operations
class operations { public: int add(); operations(int i, int j); private: int op1;//Operand 1 int op2;//Operand 2 }; |
該類的構(gòu)造函數(shù)接受兩個整數(shù)參數(shù),并將其分別設(shè)置為私有變量 op1 和 op2。該類的 add 方法如清單 2 中所示。這個方法就是要作為 XML-RPC 服務(wù)公開的方法。
清單 2. Operations.cpp
int operations::add() { std::cout << "Sum of "<<op1<<" + "<<op2<<" = "<<op1+op2<<std::endl; return(op1 + op2); } |
XML-RPC 庫的組件
在此部分,我們將使用一個類關(guān)系圖來說明 XML-RPC 庫的各個組件,并介紹其如何與我們服務(wù)器端的 operations 類通過接口連接。
圖 3. XML-RPC 庫和示例應(yīng)用程序的類關(guān)系圖

表 3 對每個類進(jìn)行了詳細(xì)說明。
表 3. 類詳細(xì)信息
類名稱 |
用途 |
Operations |
要公開的 add 方法在該類中實現(xiàn) |
Add |
調(diào)用 operations 的 add 方法的包裝類。該類也從 myXmlRpcServerMethod 繼承 |
myXmlRpcServerMethod |
該類從 XML-RPC 庫的 XmlRpcServerMethod 類繼承。該類的 execute 將在 Add 類中通過繼承覆蓋。 |
xmlRpcServermethod |
需要向服務(wù)器注冊的每個方法都必須通過 myXmlRpcServerMethod 類從該類進(jìn)行繼承,并實現(xiàn)自己的 execute 方法。這個 execute 方法將為公開的實際服務(wù)的包裝。服務(wù)器收到 XML-RPC 調(diào)用時,將會直接觸發(fā)此包裝類的 execute 方法。在我們的示例中,Add 將為包裝類,從客戶端調(diào)用“Add”服務(wù)時,將調(diào)用其 execute 方法。 |
myXmlRpcServer |
該類具有兩個重要的私有變量
- pm_serverMethods:指向在服務(wù)器中注冊的 myXmlRpcServerMethods 的指針列表。
- pm_xmlRpcServer:用于設(shè)置服務(wù)器 IP、端口和其他屬性。
三個重要的方法
- Class constructor:使用 IP/端口詳細(xì)信息初始化服務(wù)器對象,并將其綁定。
- pm_registerMethods:創(chuàng)建指向 Add 類的指針對象,并將其加入列表 pm_serverMethods 中。
- run:xmlRpcServer 類中 work 方法的包裝
|
xmlRpcServer |
該類是創(chuàng)建服務(wù)器對象的 XML-RPC 服務(wù)器類。該類具有以下兩個重要的方法
- bindAndListen(port):綁定并偵聽指定的特定端口
- work(...):啟動服務(wù)器
|
清單 3 顯示了上表中每個類的每個 .cpp 文件的代碼。由于 xmlRpcServer 和 xmlRpcServerMethod 是在 XML-RPC 庫中實現(xiàn)的,因此我們將重點討論剩下的四個類。
清單 3. myXmlRpcServer.cpp
#include "myXmlRpcServer.h" using namespace XmlRpc; using namespace std; myXmlRpcServer::myXmlRpcServer() { //call register methods pm_registerMethods(); //set port bind and listen int port = 8085; pm_xmlRpcServer.bindAndListen(port); std::cout<<"XmlRpcSever running in port "<<port<<std::endl; } void myXmlRpcServer::pm_registerMethods() { Add* a=new Add(&pm_xmlRpcServer); myXmlRpcServerMethod *p=a; pm_serverMethods.push_back(p); } void myXmlRpcServer::run() { pm_xmlRpcServer.work(-1); } |
清單 4. myXmlRpcServer.h
#include <iostream> #include "myXmlRpcServerMethods.h" #include "XmlRpc.h" class myXmlRpcServer { public: myXmlRpcServer(); void run(); private: void pm_registerMethods(); XmlRpc::XmlRpcServer pm_xmlRpcServer; std::list< myXmlRpcServerMethod* > pm_serverMethods; }; |
清單 5 和清單 6 顯示了用于將方法注冊到 XmlRpc Server(作為 XML-RPC 庫的一部分提供)的類的代碼。
清單 5. myXmlRpcServerMethods.cpp
#include <iostream> #include "myXmlRpcServer.h" #include "operations.h" using namespace std; Add::Add(XmlRpcServer* s) : myXmlRpcServerMethod("Add", s) {}; Void Add::execute(XmlRpcValue & params, XmlRpcValue& result) { operations a(10,12); try { cout << "Inside Add::execute method\n"; result = a.add(); } catch(std::exception & stde) { throw XmlRpcException(stde.what()); } } |
清單 6. myXmlRpcServerMethods.h
class myXmlRpcServerMethod : public XmlRpcServerMethod { public: myXmlRpcServerMethod (const char *name, XmlRpcServer * server):XmlRpcServerMethod(name, server) {} virtual void execute(XmlRpcValue & params, XmlRpcValue& result) {assert(0);} }; class Add:public myXmlRpcServerMethod { public: Add(XmlRpcServer* s); virtual void execute(XmlRpcValue & params, XmlRpcValue& result); }; |
服務(wù)器驅(qū)動程序
服務(wù)器端的入口點將是服務(wù)器驅(qū)動程序。將從此處實例化 myXmlRpcServer 對象,并調(diào)用 run() 方法,而后者將最終啟動服務(wù)器。
清單 7. myServerDriver.cpp
#include <iostream> #include "myXmlRpcServer.h" int main(int argc, char* argv[]) { myXmlRpcServer GeeBoomBaa; std::cout<<"About to run the server\n"; GeeBoomBaa.run(); return 0; } |
啟動服務(wù)器
為了編譯該代碼,請記住包含 (XML_RPC_INSTALL_DIR)/src 和 (XML_RPC_INSTALL_DIR)/include 目錄。為了進(jìn)行鏈接,請包含 libXmlRpc.a 庫。代碼成功編譯并鏈接后,將獲得一個可執(zhí)行文件,該文件就是 XML-RPC 服務(wù)器。在我們的示例實現(xiàn)中,服務(wù)器將運(yùn)行于 localhost 上,并偵聽端口 8085。這個設(shè)置硬編碼在 myXmlRpcServer.cpp 文件中。也可以使程序讀取配置文件,或者從命令行提示符將此作為參數(shù)傳遞給程序。運(yùn)行成功進(jìn)行了編譯和鏈接后得到的 a.out 程序,以啟動服務(wù)器。
示例客戶機(jī)
示例客戶機(jī)應(yīng)該從 XML-RPC 庫提供的 XmlRpcClient 類實例化一個對象。該類的“execute(...)”將實際接受三個參數(shù):
- 方法名稱,const char* 類型
- 端口號,const int 類型
- 可選的 URL 字符串,以作為 http get header 中的 URI 進(jìn)行發(fā)送
清單 8 顯示了一個示例客戶機(jī),此客戶機(jī)將執(zhí)行“add(...)”方法,并在客戶端輸出結(jié)果。
清單 8. sampleClient.cpp
#include <iostream> #include "XmlRpc.h" using namespace XmlRpc; int main(int argc, char* argv[]) { const char *server = "localhost"; const int port = 8085; const char *uri = NULL; XmlRpcValue args, res; XmlRpcClient c( server, port, uri); c.execute("Add", args, res); std::cout<<"result is "<<res<<std::endl; } |
結(jié)束語
XML-RPC 是一個簡單而強(qiáng)大的輕量級消息傳遞協(xié)議,可支持基于 XML 的跨異類平臺通信。此標(biāo)準(zhǔn)固有的簡單性在將遺留應(yīng)用程序與企業(yè)集成方面表現(xiàn)得非常強(qiáng)大而實用。由于各個 XML-RPC 實現(xiàn)都是開放源代碼的,使得此技術(shù)在企業(yè)應(yīng)用程序集成領(lǐng)域越來越受歡迎。隨著越來越多的成熟 XML-RPC 工具的出現(xiàn),我們可以預(yù)見,在不久的將來,此技術(shù)將成為企業(yè)內(nèi)部集成的“事實”標(biāo)準(zhǔn)。
參考資料
學(xué)習(xí)
獲得產(chǎn)品和技術(shù)
討論
作者簡介

|

|

|
Karthik Subbian 目前在班加羅爾的 IBM India Software Laboratory 進(jìn)行為制造企業(yè)構(gòu)建優(yōu)化產(chǎn)品方面的工作。他還具備幫助客戶管理應(yīng)用程序并將其遷移到 IBM 平臺方面的經(jīng)驗。他感興趣的軟件領(lǐng)域包括網(wǎng)格計算、XML、Web 服務(wù)和 SOA。他曾與他人合著了多本有關(guān)網(wǎng)格計算技術(shù)的 IBM 紅皮書。他是 IBM 認(rèn)證 XML 解決方案開發(fā)人員和 Sun 認(rèn)證 Java 程序員。 |

|

|

|
Ramakrishnan Kannan 在班加羅爾的 IBM India Software Laboratory 進(jìn)行主機(jī)集成方面的工作。他曾擔(dān)任過 IBM 個人通信和通信服務(wù)器產(chǎn)品方面的開發(fā)人員。除了承擔(dān)的開發(fā)工作外,他還與 IBM 亞太區(qū)的客戶合作進(jìn)行為主機(jī)應(yīng)用程序啟用 Web 服務(wù)方面的工作。他曾為 Infosys 等 developerWorks 的業(yè)務(wù)合作伙伴舉辦過旨在提高 Web 服務(wù)意識的培訓(xùn)。他是 IBM 認(rèn)證 XML 解決方案開發(fā)人員和 Sun 認(rèn)證 Java 程序員。他感興趣的領(lǐng)域包括主機(jī)集成、分布式計算、SOA 和網(wǎng)絡(luò)。 |