RMI示例
下面以一個例子說明怎麼使用RMI技術。這個例子演示了怎樣將一個文件上傳到服務器和怎樣將一個文件從服務器上下載下來。
利用RMI for Eclipse插件開發RMI需要以下步驟:
(1)定義和實現遠端接口中的參數
(2) 定義和實現遠端接口
(3) 編寫服務端代碼
(4)編寫客戶端代碼
部署按以下步驟:
(1)點擊Start Local registry
(2)右鍵點擊項目,選擇RMI,點擊Enable Stubs Generation
(3)運行服務器,run as-->run RMI Application:設置:RMI VM Properties:codebase 選擇compute from classpath
(4)運行客戶端,run as-->run RMI Application:設置:RMI VM Properties:security.policy新建一個即可。
下面是示例代碼:
定義和實現遠端接口中的參數
(1)定義遠端接口中的參數
每一個遠端接口中的參數都必須是可序列化的。那麼,如何定義一個序列化的接口呢,簡單,只需從java.io.Serializable繼承即可,如下所示:
import java.io.Serializable;
public interface FileInformation extends Serializable {
String getName();
byte[] getContent();
void setInformation(String name , byte[] content);
};
(2)實現遠端接口中的參數。
實現遠端接口中的參數的接口跟與實現其他任何接口沒什麼不一樣的地方,如下所示
public class FileInformationSev implements FileInformation {
private String name = null ;
private byte[] content = null ;
public String getName() {
return name ;
}
public byte[] getContent() {
return content;
}
public void setInformation(String name, byte[] content) {
this.name = name ;
this.content = content ;
}
}
那麼,爲什麼要序列化遠端接口中的參數(返回值) ?這是因爲需要將客戶端的對象(參數)轉化成byte stream,通過網絡協議傳輸到服務端,再還原成服務端的對象進行調用。或者是需要將服務端的對象(返回值)轉化成byte stream,通過網絡協議傳輸到服務端,再還原成客戶端的對象進行調用。
在 jdk中, java.lang包和java.util包下的類都已經實現了序列化,直接可以用在遠程接口中作參數或返回值;所有的基本類型也可以直接用在遠程接口中作參數或返回值;
定義和實現遠端接口
(1)定義遠端接口
遠端接口必須從java.rmi.Remote繼承;遠端接口中的方法如果要throw異常,這個異常必須是java.rmi.RemoteException(或java.rmi.RemoteException的子類),否則,這個異常就不能被返回到客戶端。Example如下:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface LoadFile extends Remote {
void upLoadFile(FileInformation fileInof) throws RemoteException;
FileInformation downLoadFile(String filename) throws RemoteException ;
}
2)實現遠端接口
實現遠端接口比較容易,跟其他接口的實現沒有什麼區別,如下所示:
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.io.IOException;
import java.io.File;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.rmi.server.UnicastRemoteObject;
public class LoadFileService extends UnicastRemoteObject implements LoadFile {
private String currentDir= null ;
// this contruction is needed
public LoadFileService() throws RemoteException { feedom.net國內最早的網管網站
super();
}
public void setCurrentDir(String currentDir){
this.currentDir = currentDir ;
}
public void upLoadFile(FileInformation fileInfo) throws RemoteException{
BufferedOutputStream output = null ;
try{
// check paramter
if(fileInfo == null ){
throw new RemoteException("the paramter is null ");
}
//check fileName and content
String fileName = fileInfo.getName() ;
byte [] content = fileInfo.getContent() ;
if(fileName == null || content == null ){
throw new RemoteException("the file or the content is null ");
}
//create file
String filePath = this.currentDir + "//" + fileName ;
File file = new File(filePath);
if(!file.exists()){
blog.bitsCN.com網管博客等你來搏
file.createNewFile();
}
//save the content to the file
output = new BufferedOutputStream(new FileOutputStream(file));
output.write(content);
}catch(RemoteException ex){
throw ex ;
}catch(Exception ex){
throw new RemoteException(ex.getLocalizedMessage());
}finally{
if(output != null ){
try{
output.close();
output = null ;
}catch(Exception ex){
}
}
}
}
public FileInformation downLoadFile(String fileName) throws RemoteException {
FileInformation fileInfo = null ;
BufferedInputStream input = null ;
try{
// check paramter
if(fileName == null){
throw new RemoteException("the paramter is null ");
}
// get path
String filePath = this.currentDir + "//" + fileName ;
File file = new File(filePath);
if(!file.exists()){
throw new RemoteException("the file whose name is " + fileName + " not existed ");
}
// get content
byte[] content = new byte[(int)file.length()];
input = new BufferedInputStream(new FileInputStream(file));
input.read(content);
// set file name and content to fileInfo
fileInfo = new FileInformationSev();
fileInfo.setInformation(fileName , content);
}catch(RemoteException ex){
throw ex ;
}catch(Exception ex){
throw new RemoteException(ex.getLocalizedMessage());
}finally{
if(input != null ){
try{
dl.bitsCN.com網管軟件下載
input.close();
input = null ;
}catch(Exception ex){
}
}
}
return fileInfo ;
}
}
編寫服務端代碼
服務端代碼主要有3個步驟:
(1)加載安全管理器
(2)創建一個服務對象
(3)將這個服務對象註冊到命名服務上
:
import java.rmi.RMISecurityManager;
import java.rmi.Naming;
public class RMIServer {
public static void main(String[] args) {
try{
//加載安全管理器
System.setSecurityManager(new RMISecurityManager() );
//創建一個服務對象
LoadFileService server = new LoadFileService();
server.setCurrentDir("c://rmiexample");
//將服務對象註冊到rmi註冊服務器上,而不是其他服務器
//(因爲LoadFileService extends UnicastRemoteObject)
Naming.rebind("//127.0.0.1:2000/LoadFileServer", server);
}catch(Exception ex){
System.out.println(ex.getLocalizedMessage());
ex.printStackTrace();
}
}
}
注意:將對象註冊以後,不可關閉服務對象。
編寫客戶端代碼
客戶端代碼需要兩個步驟:
(1)根據服務的名稱,查找服務對象
(2)調用服務服務對象對應的方法完成工作
在這個例子中,我們從客戶端上傳一個文件到服務器,並將服務器的一個文件下載下來。
代碼如下:
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import rmi.common.*;
/*
* 客戶端代碼需要兩個步驟:
(1)根據服務的名稱,查找服務對象
(2)調用服務服務對象對應的方法完成工作
*/
public class CallLoadTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
// 注意,這裏必須使用接口LoadFile,不能使用他的實現類LoadFileImpl
LoadFile loadFile=(LoadFile)Naming.lookup("test");
FileInformation fileInfo=loadFile.downLoadFile("sdatlog.txt");
byte[] content=fileInfo.getContent();
for(byte b:content)
System.out.println(b);
//System.out.println(fileInfo.getContent().toString());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NotBoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
按照上文部署即可。