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

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

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

表 3 對每個類進行了詳細說明。
表 3. 類詳細信息
類名稱 |
用途 |
Operations |
要公開的 add 方法在該類中實現 |
Add |
調用 operations 的 add 方法的包裝類。該類也從 myXmlRpcServerMethod 繼承 |
myXmlRpcServerMethod |
該類從 XML-RPC 庫的 XmlRpcServerMethod 類繼承。該類的 execute 將在 Add 類中通過繼承覆蓋。 |
xmlRpcServermethod |
需要向服務器注冊的每個方法都必須通過 myXmlRpcServerMethod 類從該類進行繼承,并實現自己的 execute 方法。這個 execute 方法將為公開的實際服務的包裝。服務器收到 XML-RPC 調用時,將會直接觸發此包裝類的 execute 方法。在我們的示例中,Add 將為包裝類,從客戶端調用“Add”服務時,將調用其 execute 方法。 |
myXmlRpcServer |
該類具有兩個重要的私有變量
- pm_serverMethods:指向在服務器中注冊的 myXmlRpcServerMethods 的指針列表。
- pm_xmlRpcServer:用于設置服務器 IP、端口和其他屬性。
三個重要的方法
- Class constructor:使用 IP/端口詳細信息初始化服務器對象,并將其綁定。
- pm_registerMethods:創建指向 Add 類的指針對象,并將其加入列表 pm_serverMethods 中。
- run:xmlRpcServer 類中 work 方法的包裝
|
xmlRpcServer |
該類是創建服務器對象的 XML-RPC 服務器類。該類具有以下兩個重要的方法
- bindAndListen(port):綁定并偵聽指定的特定端口
- work(...):啟動服務器
|
清單 3 顯示了上表中每個類的每個 .cpp 文件的代碼。由于 xmlRpcServer 和 xmlRpcServerMethod 是在 XML-RPC 庫中實現的,因此我們將重點討論剩下的四個類。
清單 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); }; |
服務器驅動程序
服務器端的入口點將是服務器驅動程序。將從此處實例化 myXmlRpcServer 對象,并調用 run() 方法,而后者將最終啟動服務器。
清單 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; } |
啟動服務器
為了編譯該代碼,請記住包含 (XML_RPC_INSTALL_DIR)/src 和 (XML_RPC_INSTALL_DIR)/include 目錄。為了進行鏈接,請包含 libXmlRpc.a 庫。代碼成功編譯并鏈接后,將獲得一個可執行文件,該文件就是 XML-RPC 服務器。在我們的示例實現中,服務器將運行于 localhost 上,并偵聽端口 8085。這個設置硬編碼在 myXmlRpcServer.cpp 文件中。也可以使程序讀取配置文件,或者從命令行提示符將此作為參數傳遞給程序。運行成功進行了編譯和鏈接后得到的 a.out 程序,以啟動服務器。
示例客戶機
示例客戶機應該從 XML-RPC 庫提供的 XmlRpcClient 類實例化一個對象。該類的“execute(...)”將實際接受三個參數:
- 方法名稱,const char* 類型
- 端口號,const int 類型
- 可選的 URL 字符串,以作為 http get header 中的 URI 進行發送
清單 8 顯示了一個示例客戶機,此客戶機將執行“add(...)”方法,并在客戶端輸出結果。
清單 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; } |
結束語
XML-RPC 是一個簡單而強大的輕量級消息傳遞協議,可支持基于 XML 的跨異類平臺通信。此標準固有的簡單性在將遺留應用程序與企業集成方面表現得非常強大而實用。由于各個 XML-RPC 實現都是開放源代碼的,使得此技術在企業應用程序集成領域越來越受歡迎。隨著越來越多的成熟 XML-RPC 工具的出現,我們可以預見,在不久的將來,此技術將成為企業內部集成的“事實”標準。
參考資料
學習
獲得產品和技術
討論
作者簡介

|

|

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

|

|

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