《Thinking in Java》RMI遠程方法示例代碼運行是可能遇到的問題及解決方法

轉自:http://ajava.org/course/net/541.html

在Think In Java裏有一個示例 RMI 的代碼 PerfectTime, 可是其中並沒有把有些執行細節說明了,也就可以造成新手運行它會出某些異常而不知所措。下面將列出可能產生的異常,並說明解決辦法,如讀者在執行當中還遇到其他未列出的異常,可留言告知,吾將盡力而爲。

首先把代碼PerfectTime和DisplayPerfectTime 中的//colossus:2005/PerfectTime改爲//localhost:2005/PerfectTime ,因爲colossus爲機器名,所以改爲localhost指向本機,不然找不到主機colossus的。

使用rmic編譯時,要是使用rmic -v1.1 -keep XXXImpl 纔會生成_Skel and _Stub;我在jdk1.5環境下直接使用rmic XXXImpl之生成了_Stub;
已經用命令 RMIC 生成PerfectTime_Stub.class,並且執行了命令 rmiregistry 2005

1. 執行java PerfectTime出現異常 java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:2005 connect,resolve)

無法解析和連接到127.0.0.1的2005端口上,原因是在PerfectTime中設置了安全管理器<System.setSecurityManager(new RMISecurityManager());>,可是又沒有設置訪問的策略,解決辦法有四(解決這種異常的辦法同樣適用於DisplayPerfectTime):

(1) 可以把代碼System.setSecurityManager(new RMISecurityManager());去掉,不設置安全管理器
(2) 修改JRE的安全策略文件,這就要求你能確定執行時是用的哪個JRE,比如在Eclipse中用JDK是c:/Java/jdk1.5.0_06,相應的安全策略文件就是c:/java/jdk1.5.0_06/jre/lib/security/java.policy,如果是Applet中的java程序就應該是在 jre 目錄中,如文件C:/Java/jre1.5.0_06/lib/security/java.policy。修改安全策略文件,在grant {},大括號中加上permission java.net.SocketPermission "localhost:2005","connect,resolve";
(3) 建立自己的策略文件,如c:/MyPolicy.policy ,內容爲:

  1. grant {    
  2. permission java.net.SocketPermission "localhost:2005","connect,resolve";    
  3. }   



執行PerfectTime時用命令 java -Djava.security.policy=c:/MyPolicy.policy PerfectTime  指定了安全策略文件

(4) 把 System.setSecurityManager (new RMISecurityManager()) 改爲匿名類實現,覆蓋兩個方法

  1. System.setSecurityManager (new RMISecurityManager() {    
  2. public void checkConnect (String host, int port) {}    
  3. public void checkConnect (String host, int port, Object context) {}    
  4. });   



當然最簡單的解決方法莫過於第一種。

2. 同樣是執行 PerfectTime 出現的異常

  1. java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:    
  2. java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:    
  3. java.lang.ClassNotFoundException: PerfectTime_Stub   


很多人對這個問題有些莫名其妙,因爲明明看到 PerfectTime_Stub 和 PerfectTime 這兩個類是在同一個目錄中,並且classpath 也有設置當前目錄,按理既然能加載 PerfectTime 類執行,就能加載到 PerfectTime_Stub吧,爲什麼還提示ClassNotFound呢?其實類 PerfectTime_Stub並非由PerfectTime執行行直接加載,而是PerfectTime在向RMI註冊時,要求rmiregistry去加載 PerfectTime_Stub類的,理解了這一層次上的意義就會知道其實 PerfectTime_Stub是爲 rmiregistry所用的。所以解決辦法是:

(1) 在執行 rmiregistry 之前,設置classpath讓能查找到PerfectTime_Stub類,如在同一Dos窗口中,假設 PerfectTime_Stub類是在E:/workspace/TestRMI/bin目錄中,執行過程那就是

C:/Documents and Settings/unmi>set classpath=%classpath%;E:/workspace/TestRMI/bin

C:/Documents and Settings/unmi>rmiregistry 2005

(2) 或者在命令行中先進入到 PerfectTime_Stub類所在的目錄,然後再執行 rmiregistry (這種方法實質是與上面一樣的,只是恰當的應用的classpath中的當前目錄 "." ),執行過程如下

C:/Documents and Settings/unmi>e:

E:/>cd E:/workspace/TestRMI/bin

E:/workspace/TestRMI/bin>rmiregistry 2005

參看:rmiregistry was finding the stubs in its CLASSPATH

3. 執行客戶端程序 DisplayPerfectTime 出現異常 java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:1276 connect,resolve),同時在服務器端也產生異常 Exception in thread "RMI TCP Connection(6)-127.0.0.1" java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:1296 accept,resolve)

直接能想到的解決辦法是把127.0.0.1:1276,127.0.0.1:1276的解析連接權限也加上,方法可取第 1 種異常所列的方法,但這個端口是隨機的。在此解析一下這些端口的用途,2005是直接指定的供客戶端查找註冊的服務對象引用的端口,這是固定的,而上面產生的在客戶端和服務器上的1276和1296的端口,是隨機的,是在方法調用時真正的客戶端與提供服務的服務器(而非註冊服務器)之間的數據通信的端口。

爲了滿足上面的端口應用,可以在安全策略文件中只加上 permission java.net.SocketPermission "localhost:*","accept,connect,resolve"; 允許在所有端口上的接受,連接,解析。再如果要訪問的IP很多,又要寫成 permission java.net.SocketPermission "*:*","accept,connect,resolve"; 方便。

4. 執行客戶端程序 DisplayPerfectTime出現異常  java.rmi.UnmarshalException: Error unmarshaling return header; nested exception is: java.io.EOFException,這種異常應該比較少見,出現情況是 客戶端有權限訪問服務提供端的某個端口,而服務提供端卻無權限在某個端口上或給那個客戶端提供服務造成的,解決辦法把客戶端和服務器的安全策略文件都改爲能訪問任何端口就行。

總結:上面1、3、4三種情況都是因爲權限不足所造成的,如果安全控制的粒度不要求太細的化,在服務器端和客戶端可以不用設置定全管理器,或者策略文件中設置爲能接受、連接、解析任何IP及端口:permission java.net.SocketPermission "*:*","accept,connect,resolve"; 或者用1(4)的方法忽略所有IP及端口的檢測。

發佈了17 篇原創文章 · 獲贊 12 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章