RMI(
远程接口调用)
1. RMI的原理:
RMI系统结构,在客户端和服务器端都有几层结构。
方法调用从客户对象经占位程序(Stub)、远程引用层(Remote Reference Layer)和传输层(Transport Layer)向下,传递给主机,然后再次经传 输层,向上穿过远程调用层和骨干网(Skeleton),到达服务器对象。 占位程序扮演着
远程服务器对象的代理的角色,使该对象可被客户激活。 远程引用层处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。传输层管理实际的连接,并且追追踪可以接受方法调用的远程对象。服务器端的骨干网完成对服务器对象实际的方法调用,并获取返回值。返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,占位程序获得返回值。
2. RMI(远程方法调用)的组成
一个正常工作的RMI系统由下面几个部分组成:
? ?远程服务的接口定义
? ?远程服务接口的具体实现
? ?桩(Stub)和框架(Skeleton)文件
? ?一个运行远程服务的服务器
? ?一个RMI命名服务,它允许客户端去
发现这个远程服务
? ?类文件的提供者(一个
HTTP或者FTP服务器)
????? ?一个需要这个远程服务的客户端程序
3. RMI的实现
(1) 服务器端的实现
编写一个远程接口
Java代码
?
class="star" alt="收藏代码" src="/Upload/Images/2013073122/40B102E0EF997EA6.png">
spinner" alt="" style="display: none;" src="/Upload/Images/2013073122/4E072B8B8C20032D.gif">
- package?com.gjy.rmi.service; ??
- ??
-
import?java.rmi.Remote; ??
-
import?java.rmi.RemoteException; ??
- ??
- ??
-
public?interface?AddServer?extends?Remote?{? ??
-
????public?int?AddNumbers(int?firstnumber,int?secondnumber)?throws?RemoteException;? ??
- }??
package com.gjy.rmi.service;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface AddServer extends Remote {
public int AddNumbers(int firstnumber,int secondnumber) throws RemoteException;
}
(2) 编写远程接口的实现
Java代码
?
- package?com.gjy.rmi.service; ??
- ??
-
import?java.rmi.RemoteException; ??
-
import?java.rmi.server.UnicastRemoteObject; ??
- ??
-
public?class?AddServerImpl?extends?UnicastRemoteObject?implements?AddServer?{? ??
-
????public?AddServerImpl()?throws?RemoteException?{? ??
-
????????super();? ??
- ????}? ??
-
????public?int?AddNumbers(int?firstnumber,int?secondnumber)?throws?RemoteException?{? ??
-
????????return?firstnumber?+?secondnumber;? ??
- ????}? ??
- }??
package com.gjy.rmi.service;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class AddServerImpl extends UnicastRemoteObject implements AddServer {
public AddServerImpl() throws RemoteException {
super();
}
public int AddNumbers(int firstnumber,int secondnumber) throws RemoteException {
return firstnumber + secondnumber;
}
}
(3) 编写服务器端程序
Java代码
?
- package?com.gjy.rmi.service; ??
- ??
-
import?java.rmi.Naming; ??
-
import?java.rmi.registry.LocateRegistry; ??
- ??
-
public?class?RmiServer?{? ??
-
??????
- ?
- ??? ??
-
???????public?static?void?main(String[]?argv)???? ??
- ???????{???? ??
-
??????????try??? ??
- ??????????{???? ??
-
???????????????
-
???????????????
-
???????????????
-
???????????????
-
?????????????LocateRegistry.createRegistry(1099);???? ??
- ???????????????? ??
-
???????????????
-
???????????????
-
?????????????AddServer?add?=?new?AddServerImpl();???? ??
- ???????????????? ??
-
???????????????
-
?????????????Naming.rebind("Hello",?add);???? ??
- ????????????????? ??
-
???????????????
-
???????????????
- ???????????????? ??
-
?????????????System.out.println("Hello?Server?is?ready.");???? ??
- ??????????}???? ??
-
??????????catch?(Exception?e)???? ??
- ??????????{???? ??
-
?????????????System.out.println("Hello?Server?failed:?"?+?e);???? ??
- ??????????}???? ??
- ???????}??? ??
- }??
package com.gjy.rmi.service;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
public class RmiServer {
/**
* 启动 RMI 注册服务并进行对象注册
*/
public static void main(String[] argv)
{
try
{
//启动RMI注册服务,指定端口为1099 (1099为默认端口)
//也可以通过命令 $java_home/bin/rmiregistry 1099启动
//这里用这种方式避免了再打开一个DOS窗口
//而且用命令rmiregistry启动注册服务还必须事先用RMIC生成一个占位程序(stub类)为它所用
LocateRegistry.createRegistry(1099);
//创建远程对象的一个或多个实例,下面是hello对象
//可以用不同名字注册不同的实例
AddServer add = new AddServerImpl();
//把hello注册到RMI注册服务器上,命名为Hello
Naming.rebind("Hello", add);
//如果要把hello实例注册到另一台启动了RMI注册服务的机器上
//Naming.rebind("//192.168.1.105:1099/Hello",hello);
System.out.println("Hello Server is ready.");
}
catch (Exception e)
{
System.out.println("Hello Server failed: " + e);
}
}
}
(4) 编写客户端程序
Java代码
?
- package?com.gjy.rmi.client; ??
- ??
-
import?java.net.MalformedURLException; ??
-
import?java.rmi.Naming; ??
-
import?java.rmi.NotBoundException; ??
-
import?java.rmi.RemoteException; ??
- ??
-
import?com.gjy.rmi.service.AddServer; ??
- ??
-
public?class?RmiClient?{? ??
-
public?static?void?main(String?args[])?throws?RemoteException,?MalformedURLException,?NotBoundException?{? ??
-
????????String?url="rmi://127.0.0.1/Hello";? ??
- ????????AddServer?add;? ??
- ????????add?=?(AddServer)Naming.lookup(url);? ??
-
????????int?result=0; ??
-
????????for?(int?i?=0;i<10;i++){ ??
-
????????result?=?add.AddNumbers(10,i); ??
- ????????System.out.println(result);? ??
- ????????} ??
- ????}? ??
- }??
package com.gjy.rmi.client;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import com.gjy.rmi.service.AddServer;
public class RmiClient {
public static void main(String args[]) throws RemoteException, MalformedURLException, NotBoundException {
String url="rmi://127.0.0.1/Hello";
AddServer add;
add = (AddServer)Naming.lookup(url);
int result=0;
for (int i =0;i<10;i++){
result = add.AddNumbers(10,i);
System.out.println(result);
}
}
}