遠程過程調用概述-RMI簡介
簡介:
RPC是遠程過程調用(Remote Procedure Call)的縮寫形式。SAP系統RPC調用的原理其實很簡單,有一些類似於三層構架的C/S系統,第三方的客戶程序通過接口調用SAP內部的標準或自定義函數,獲得函數返回的數據進行處理後顯示或打印。RPC采用客戶機/服務器模式。請求程序就是一個客戶機,而服務提供程序就是一個服務器。首先,客戶機調用進程發送一個有進程參數的調用信息到服務進程,然後等待應答信息。在服務器端,進程保持睡眠狀態直到調用信息到達為止。當一個調用信息到達,服務器獲得進程參數,計算結果,發送答復信息,然後等待下一個調用信息,最後,客戶端調用進程接收答復信息,獲得進程結果,然後調用執行繼續進行。
遠程調用流程圖:
工作原理:
運行時,一次客戶機對服務器的RPC調用,其內部操作大致有如下十步:
1.調用客戶端句柄;執行傳送參數
2.調用本地系統內核發送網絡消息
3.消息傳送到遠程主機
4.服務器句柄得到消息並取得參數
5.執行遠程過程
6.執行的過程將結果返回服務器句柄
7.服務器句柄返回結果,調用遠程系統內核
8.消息傳回本地主機
9.客戶句柄由內核接收消息
10.客戶接收句柄返回的數據
遠程調用的幾種方式:
在java領域中知名的有:RMI、XML-RPC、Binary-RPC、SOAP、CORBA、JMS等。
1.RMI
RMI是個典型的為java定制的遠程通信協議, 我們都知道,在single vm中,我們能夠通過直接調用java object instance來實現通信,那麽在遠程通信時,假設也能依照這樣的方式當然是最好了。這樣的遠程通信的機制成為RPC(RemoteProcedure Call),RMI正是朝著這個目標而誕生的。傳輸的標準格式是Java Object Stream;基於Java串行化機制將請求的Java Object信息轉化為流。傳輸協議是Socket。
2.XML-RPC
XML-RPC也是一種和RMI類似的遠程調用的協議,它和RMI的不同之處在於它以標準的xml格式來定義請求的信息(請求的對象、方法、參數 等),這種優點是在跨語言通訊的時候也能夠使用。所以RMI與RPC的差別之中的一個是RPC是跨語言的。 傳輸的標準格式是XML。將XML轉化為流。傳輸協議是HTTP。
3.Binary-RPC
Binary-RPC和XML-RPC是差點兒相同,不同之處僅在於傳輸的標準格式由XML轉為了二進制的格式。 傳輸的標準格式是二進制文件。將二進制文件轉化為傳輸的流。傳輸協議是HTTP。
4.SOAP
SOAP(SimpleObject Access Protocol),是一個用於分布式環境的、輕量級的、基於XML進行信息交換的通信協議,能夠覺得SOAP是XML RPC的高級版。兩者的原理全然同樣。都是http+XML,不同的僅在於兩者定義的XML規範不同。SOAP也是Webservice採用的服務調用協議標準。
5.CORBA
Common Object Request BrokerArchitecture(公用對象請求代理[調度]程序體系結構),是一組用來定義“分布式對象系統”的標準,由OMG(Object Menagement Group)作為發起和標準制定單位。CORBA的目的是定義一套協議,符合這個協議的對象能夠互相交互,不論它們是用什麽樣的語言寫的。不論它們執行於 什麽樣的機器和操作系統。CORBA是個類似於SOA的體系架構。涵蓋可選的遠程通信協議,但其本身不能列入通信協議。
6.JMS
JMS是實現java領域遠程通信的一種手段和方法。基於JMS實現遠程通信時和RPC是不同的。盡管能夠做到RPC的效果,但由於不是從協議 級別定義的。因此我們不覺得JMS是個RPC協議,但它確實是個遠程通信協議,在其它的語言體系中也存在著類似JMS的東西,能夠統一的將這類機制稱為消 息機制。而消息機制呢,一般是高並發、分布式領域推薦的一種通信機制,這裏的主要一個問題是容錯。JMS註重的是消息交換,RMI註重的是對象方法調用,所以目的不同。JMS大多時候是異步的松耦合,RMI大多時候是同步的緊耦合。JMS規定的傳輸格式是Message,將參數信息放入Message中,傳輸協議不限。基於JMS也是經常使用的實現遠程異步調用的方法之中的一個。
RMI介紹
遠程方法調用(RMI)顧名思義是一臺機器上的程序調用另一臺機器上的方法。這樣可以大致知道RMI是用來幹什麽的,但是這種理解還不太確切。RMI是Java支撐分布式系統的基石,例如著名的EJB組件。RMI是遠程過程調用(RPC)的一種面向對象實現,RMI底層是通過socket通信和對象序列化技術來實現的。這裏引用Wikipedia對RMI的介紹:
RMI基本原理
RMI的目的就是要使運行在不同的計算機中的對象之間的調用表現得像本地調用一樣。RMI 應用程序通常包括兩個獨立的程序:服務器程序和客戶機程序。RMI 需要將行為的定義與行為的實現分別定義, 並允許將行為定義代碼與行為實現代碼存放並運行在不同的 JVM 上。在 RMI 中, 遠程服務的定義是存放在繼承了 Remote 的接口中。遠程服務的實現代碼存放在實現該定義接口的類中。RMI 支持兩個類實現一個相同的遠程服務接口: 一個類實現行為並運行在服務器上, 而另一個類作為一個遠程服務的代理運行在客戶機上。客戶程序發出關於代理對象的調用方法, RMI 將該調用請求發送到遠程 JVM 上, 並且進一步發送到實現的方法中。實現方法將結果發送給代理, 再通過代理將結果返回給調用者。
RMI 構建三個抽象層, 高層覆蓋低層, 分別負責Socket通信, 參數和結果的序列化和反序列化等工作。存根( Stub) 和骨架( Skeleton) 合在一起形成了 RMI 構架協議。下面的引用層被用來尋找各自的通信夥伴, 在這一層還有一個提供名字服務的部分, 稱為註冊表( registry) 。最下一層是傳輸層, 是依賴於 TCP/IP 協議實現客戶機與服務器的互聯。
當客戶端調用遠程對象方法時, 存根負責把要調用的遠程對象方法的方法名及其參數編組打包,並將該包向下經遠程引用層、傳輸層轉發給遠程對象所在的服務器。通過 RMI 系統的 RMI 註冊表實現的簡單服務器名字服務, 可定位遠程對象所在的服務器。該包到達服務器後, 向上經遠程引用層, 被遠程對象的 Skeleton 接收, 此 Skeleton 解析客戶包中的方法名及編組的參數後, 在服務器端執行客戶要調用的遠程對象方法, 然後將該方法的返回值( 或產生的異常) 打包後通過相反路線返回給客戶端, 客戶端的 Stub 將返回結果解析後傳遞給客戶程序。事實上, 不僅客戶端程序可以通過存根調用服務器端的遠程對象的方法, 而服務器端的程序亦可通過由客戶端傳遞的遠程接口回調客戶端的遠程對象方法。在分布式系統中, 所有的計算機可以是服務器, 同時又可以是客戶機。
RMI應用示例
Remote 接口用於標識其方法可以從非本地虛擬機上調用的接口。任何遠程對象都必須直接或間接實現此接口。只有在“遠程接口”(擴展 java.rmi.Remote 的接口)中指定的這些方法才可遠程使用。 也就是說需要遠程調用的方法必須在擴展Remote接口的接口中聲名並且要拋出RemoteException異常才能被遠程調用。遠程對象必須實現java.rmi.server.UniCastRemoteObject類,這樣才能保證客戶端訪問獲得遠程對象時,該遠程對象將會把自身的一個拷貝序列化後以Socket的形式傳輸給客戶端,此時客戶端所獲得的這個拷貝稱為“存根”,而服務器端本身已存在的遠程對象則稱之為“骨架”。其實此時的存根是客戶端的一個代理,用於與服務器端的通信,而骨架也可認為是服務器端的一個代理,用於接收客戶端的請求之後調用遠程方法來響應客戶端的請求。 遠程對象的接口和實現必須在客戶端和服務器端同時存在並且保持一致才行。
代碼實現:
HelloDefine.java
1 package com.etc; 2 3 import java.rmi.Remote; 4 import java.rmi.RemoteException; 5 //遠程接口定義 6 public interface HelloDefine extends Remote { 7 public String helloWorld() throws RemoteException; 8 public String sayHello(String name) throws RemoteException; 9 }
HelloDefineImp.java
1 package com.etc; 2 3 import java.rmi.RemoteException; 4 import java.rmi.server.UnicastRemoteObject; 5 //遠程接口實現 6 public class HelloDefineImp extends UnicastRemoteObject implements HelloDefine { 7 private static final long serialVersionUID = 1L; 8 public HelloDefineImp() throws RemoteException { 9 super(); 10 } 11 public String helloWorld() throws RemoteException { 12 return "Hello AlphaGo!"; 13 } 14 public String sayHello(String name) throws RemoteException { 15 return "Hello" + name +"!"; 16 } 17 }
HelloServer.java
1 package com.etc; 2 3 import java.net.MalformedURLException; 4 import java.rmi.AlreadyBoundException; 5 import java.rmi.Naming; 6 import java.rmi.RemoteException; 7 import java.rmi.registry.LocateRegistry; 8 //服務端綁定 9 public class HelloServer { 10 HelloDefine hello; 11 public void server() throws RemoteException, MalformedURLException, AlreadyBoundException { 12 hello = new HelloDefineImp(); 13 //遠程對象註冊表實例 14 LocateRegistry.createRegistry(8888); 15 //把遠程對象註冊到RMI註冊服務器上 16 Naming.bind("rmi://localhost:8888/Hello", hello); 17 System.out.println("server:對象綁定成功!"); 18 } 19 }
HelloClient.java
1 package com.etc; 2 3 import java.net.MalformedURLException; 4 import java.rmi.Naming; 5 import java.rmi.NotBoundException; 6 import java.rmi.RemoteException; 7 //客戶端調用 8 public class HelloClient { 9 public HelloDefine hello; 10 public void client() throws MalformedURLException, RemoteException, NotBoundException { 11 //在RMI註冊表中查找指定對象 12 hello = (HelloDefine) Naming.lookup("rmi://localhost:8888/Hello"); 13 //調用遠程對象方法 14 System.out.println("client:"); 15 System.out.println(hello.helloWorld()); 16 System.out.println(hello.sayHello("起飛吧騷年!")); 17 } 18 }
轉載部分內容來源:https://www.cnblogs.com/wxisme/p/5296441.html
遠程過程調用概述-RMI簡介