« | August 2025 | » | 日 | 一 | 二 | 三 | 四 | 五 | 六 | | | | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | | | | | | | |
我的分类(专题) |
|
Blog信息 |
blog名称:行百里者半九十 日志总数:38 评论数量:21 留言数量:0 访问次数:266175 建立时间:2007年8月25日 |

| |
JAVA RMI 学习 原创空间, 网上资源, 心得体会, 所见所闻, 软件技术, 职业生涯, 数码玩家, 其他
行百里者半九十 发表于 2008/9/17 20:42:57 |
由于工作途中遇到了RMI(Remote Method Invocation 远程方法调用),它是一个分布式对象系统,它使你能够轻松地开发出分布式Java应用程序。在RMI中开发分布式应用程序比用套接字开发要简单,因为不需要做设计协议这种很容易出错的工作。在RMI中,开发者会有一种错觉,似乎是从本地类文件调用的本地方法,其实参数传送给了远程目标,目标解释参数后再把结果发回给调用方。
(以上系引用为主 源:http://tech.ccidnet.com/art/3539/20080526/1457809_1.html)
在学习RMI的过程中,有一个非常明显的感觉,那就是分布式的应用采用RMI来开发应该很快!首先,RMI通过定义接口和接口实现,使得客户端调用者和服务提供者分离,这样只要不改变接口定义,客户端就不用修改,而服务端则可以用自己的方式来修改或升级。
下面来简单介绍一下RMI应用的组成,并给出个人根据网上相关资源所写的一个简单例子。通常一个RMI应用应该分为:1、服务提供者和服务享受者协商确定的接口;2、接口在服务提供方的实现;3、服务提供程序;4、客户端调用程序。下面的源代码是我在JDK1.5下调试通过的,服务端程序在被调用时,会在服务端打印信息以显示正在提供服务,而客户端也会提示接收服务的相关信息,详细过程不再赘述,看看代码就一目了然了!
1、服务提供者和服务享受者协商确定的接口:
/** * Created On 2008-9-17 By Ivan */package net.vicp.fst.rmi.operate;
import java.rmi.Remote;import java.rmi.RemoteException;
/** * @author Ivan 此接口用于定义本地和远程服务器上程序的公共接口 */public interface IOperateUtil extends Remote { /** * 读取服务器上指定文件的内容返回 * * @param absFileName * 文件在服务器上的绝对路径(含文件名称) * @return 文件内容 * @throws RemoteException */ public String readFileContent(String absFileName) throws RemoteException;
/** * 在服务器上执行命令,将命令执行的结果返回 * * @param cmd * 具体命令 * @return 命令执行结果 * @throws RemoteException */ public String execCommand(String cmd) throws RemoteException;}
2、接口在服务提供方的实现:
/** * Created On 2008-9-17 By Ivan */package net.vicp.fst.rmi.operate.impl;
import java.rmi.RemoteException;
import net.vicp.fst.rmi.operate.IOperateUtil;
/** * @author Ivan 此类是IOperateUtil接口的实现 */public class OperateUtilImpl implements IOperateUtil {
/** * 读取服务器上指定文件的内容返回 * * @param absFileName * 文件在服务器上的绝对路径(含文件名称) * @return 文件内容 * @throws RemoteException */ public String execCommand(String cmd) throws RemoteException { System.out.println("远程客户端正在调用服务器执行命令:\"" + cmd + "\" !"); System.out.println("命令\"" + cmd + "\"执行完毕!"); return "命令:\"" + cmd + "\"执行的结果是:……"; }
/** * 在服务器上执行命令,将命令执行的结果返回 * * @param cmd * 具体命令 * @return 命令执行结果 * @throws RemoteException */ public String readFileContent(String absFileName) throws RemoteException { System.out.println("远程客户端正在调用服务器读取文件:\"" + absFileName + "\"中的内容."); System.out.println("文件\"" + absFileName + "\"的内容被读取完毕!"); return "文件\"" + absFileName + "\"中的内容是:……"; }}
3、服务提供程序:
/** * Created On 2008-9-17 By Ivan */package net.vicp.fst.rmi.server;
import java.rmi.Naming;import java.rmi.RMISecurityManager;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import java.rmi.server.UnicastRemoteObject;import net.vicp.fst.rmi.operate.IOperateUtil;import net.vicp.fst.rmi.operate.impl.OperateUtilImpl;/** * @author Ivan * 此类用于启动RMI服务器 */public class FstRmiServer extends UnicastRemoteObject {
private static final long serialVersionUID = 6158084897536450551L; private IOperateUtil iou = null; protected FstRmiServer() throws RemoteException { super(); System.out.println("启动本地RMI服务器..."); } /** * 初始化RMI对象,并将RMI对象绑定到名称 */ public void startRMI(){ if(System.getSecurityManager()!=null){ System.setSecurityManager(new RMISecurityManager()); } try { iou = new OperateUtilImpl(); // 将该对象实例与名称FstRmiUtil绑定 LocateRegistry.createRegistry(1385); Naming.bind("rmi://localhost:1385/FstRmiUtil", iou); System.out.println("RMI服务启动成功!"); } catch (Exception e) { System.err.println("RMI服务启动失败!详细信息如下:"); e.printStackTrace(); } }
/** * @param args */ public static void main(String[] args) { try{ FstRmiServer server = new FstRmiServer(); server.startRMI(); }catch(Exception e){ e.printStackTrace(); } }}
4、客户端调用程序:
/** * Created On 2008-9-17 By Ivan */package net.vicp.fst.rmi.client;import java.net.MalformedURLException;import java.rmi.Naming;import java.rmi.NotBoundException;import java.rmi.RemoteException;import net.vicp.fst.rmi.operate.IOperateUtil;/** * @author Ivan 此类用于调用RMI服务器上服务 */public class FstRmiClient { public void invokeRMI(String IpAddress, String PortNumber, String ServiceName) { try { System.out.println("开始调用RMI服务..."); IOperateUtil iou = (IOperateUtil)Naming.lookup("rmi://" + IpAddress + ":" + PortNumber + "/" + ServiceName); //调用远程服务 String fileContent = iou.readFileContent("D:\\ftpRoot\\test.txt"); System.out.println(fileContent); String cmdOut = iou.execCommand("type D:\\ftpRoot\\test.txt"); System.out.println(cmdOut); System.out.println("调用RMI服务完毕!"); } catch (NotBoundException ne) { System.err.println("调用RMI服务发生 NotBoundException 异常,详细信息如下:"); ne.printStackTrace(); } catch (MalformedURLException mue) { System.err.println("调用RMI服务发生 MalformedURLException 异常,详细信息如下:"); mue.printStackTrace(); } catch (RemoteException re) { System.err.println("调用RMI服务发生 RemoteException 异常,详细信息如下:"); re.printStackTrace(); } }
/** * @param args 调用RMI服务的参数,详细入下<br> * <ul> * args[0]:RMI服务器IP地址 <br> * args[1]:RMI服务端口 <br> * args[2]:RMI服务名称 <br> * </ul> */ public static void main(String[] args) { FstRmiClient client = new FstRmiClient(); if(args.length != 3){ client.invokeRMI("192.168.1.77", "1385", "FstRmiUtil"); }else{ client.invokeRMI(args[0], args[1], args[2]); } }}
将以上程序编译,然后分别打包成jar,客户端只需要知道接口的定义和客户端本身的调用程序,而服务器端则不需要知道客户端是怎么调用,但必须知道提供服务的实现。因此,打包的时候将1 2 3打包为服务器短运行的程序,将1 4打包成为客户端运行的程序即可!
测试的时候需要在客户端指定服务方的IP,端口以及服务绑定名称,具体的测试信息不再给出! |
|
|