rmi 调用

1       RMI : Remote Method Invotion 介绍

1.1    定义-- RMI:远程方法调用。

只能用在java应用系统间的远程调用。

1.2    结构

 

  

           抽象为

           Stub()完成:1. 初始化远程调用.

2. 序列化(Marahal)发送的参数.

3. 提示远程对象应用层将进行调用.

4. 反序列化(Unmarshal)返回值(或者异常).

5. 提示远程传输层调用完成.

 

         Sket(构架)完成:1. 反序列化客户端输入参数.

                        2. 调用实际的远程对象实现

                        3. 将返回值序列化为流,传输给调用者即客户.

1.3    开发步骤

1. Develop the remote object, server, and client code
2. Compile the code
3. Run the RMI compiler (rmic)
4. Move the .class files to an appropriate location
5. Start the registry
6. Start the server
7. Start the client

1.4    用到的工具: rmic——生成客户端桩和服务器端架构

2       开发实例时间服务器

通过该实例,将掌握开发一个RMI的基本流程以及在每一个步骤中可能出现的问题以及一些解决的办法,解决问题的方式不局限于本文所提,可能有多种解决。

2.1    任务

   开发一个时间服务器,客户端通过远程调用得到服务器上面的时间。

2.3    代码实现

1.1    定义调用接口

 import java.rmi.Remote;

import java.rmi.RemoteException;

import java.rmi.*;

public interface PerfectTimeI extends Remote {

  long getPerfectTime()throws RemoteException;

}

 

必须:所定义的接口必须继承Remote.

      所有在接口中定义的方法必须抛出RemoteException

      返回的类型必须实现序列化

 

1.2    服务器端代码实现

import java.rmi.RemoteException;

import java.rmi.server.UnicastRemoteObject;

import java.rmi.registry.*;

import java.rmi.server.*;

import java.net.*;

import java.rmi.*;

 

public class PerfectTime extends UnicastRemoteObject implements PerfectTimeI {

 

         public long getPerfectTime() throws RemoteException {

              // TODO Auto-generated method stub

              return System.currentTimeMillis();

         }

         public PerfectTime()throws RemoteException{}

 

         public static void main(String[] args){

              System.setSecurityManager(new RMISecurityManager());

              try{

                     PerfectTime pt=new PerfectTime();

                     Naming.rebind(RmiServerName.RMI_SERVER_NAME, pt);

              }catch(Exception e){

                     e.printStackTrace();

              }

         }

}

说明:1. 服务器端代码必须继承UnicastRemoteObject类,并实现服务接口。               如果不继承UnicastRemoteObject类,则代码要这样写:

              PerfectTime pt= new PerfectTime()

RemoteStub stub=UnicastRemoteObject.exportObject(pt);

Naming.rebind(RmiServerName.RMI_SERVER_NAME, stub);

此外,你还得覆写equals,hashcode方法。

UnicastRemoteObject:当你要继承另一个类的时候,由于java是不支持多继承的,而你又必须继承另一个不是UnicastRemoteObject的类,此时你也许就要用到上面的代码了。当然这只是原因之一。

(not extending UnicastRemoteObject is that you might want to extend

either Activatable or PortableRemoteObject. Activatable and PortableRemote-Object are classes provided by Javasoft that play a role similar to the one played by UnicastRemoteObject

             

               (two main benefits to UnicastRemoteObject: it automatically connects to the RMI runtime and it knows how to check for equality with other remote objects. However, extending UnicastRemoteObject can sometimes cause minor problems for two reasons: it prevents server classes from subclassing other classes (because Java is a single inheritance language),

and it can sometimes prematurely expose an object to remote method calls.)

 

2. 绑定的服务名称格式: //<serverhost/ip>:<port>/ServerName。如果有多个服务接口,则该名称不能相同。

 

1.3    客户端代码实现

import java.rmi.*;

import java.rmi.registry.*;

public class DisplayPerfectTime {

    public static void main(String[] args) {

                     // TODO Auto-generated method stub

                     System.setSecurityManager(new RMISecurityManager());

                      try{

                             PerfectTimeI p=(PerfectTimeI)

Naming.lookup(RmiServerName.RMI_SERVER_NAME);

                             System.out.println(p.getPerfectTime());

                     }catch(Exception e){

                            e.printStackTrace();

                      }

               }

}

2.4    编译

1.  编译接口,服务器端程序,客户端程序,生成三个类文件。PerfectTime.classPerfectTimeI.classDisplayPerfectTime.class

2.  rmic 编译服务器端程序生成的类文件PerfectTime.class

Rmic PerfectTime

将生成PerfectTime_Stub.classPerfectTime_Skel.class两个类文件,分别是桩和架构。至此编译完成。

         说明:在jdk1.4中,rmic默认编译将生成stubskel两个文件。

               jdk1.5种,rmic默认编译将只生成stub一个文件。这是由于在1.5种,用到了反射机制,由skel文件所产生的作用可以根据反射机制得到。当然由此需要在运行时花一点时间了。

2.5    运行

1. 启动rmiregistry . 如果不加端口号,则默认打开的端口是1099

Unix :    rmiregistry  [port] &  

Windows: start rmiregistry [port]

 

2. 启动服务器端程序

   Java PerfectTime

 

3. 启动客户端程序,验证结果

   Java DisplayPerfectTime

 

需要的知识:

此处需要更多的关于javapolicy的知识。考虑到远程调用的安全性,在每个类中都用到了System.setSecurityManager 方法和RMISecurityManager类。这样在运行服务器端和客户端的时候,需要加上-Djava.security.polity参数。它指定一个policy文件。这样运行程序的时候,脚本看起来就是这样的:

Java –Djava.security.policy=myrmipolicy.policy PerfectTime 再启动rmiregistry的时候也可以加上这个参数,如果加上这个参数,则还要指定-J参数,则命令看起来是这样:rmiregistry –J-Djava.security.policy=myrmipolicy.policy [port] &

有关policy的知识,可以去java.sun.com中看相关说明。

 

自定义安全管理器:

假如想自己定义一个安全管理器,则需要继承RMISecurityManager类即可。

Public MyRmiSM extends RMISecurityManager{

           checkPermission(){

          //if you want doing things , you coding here

          //of course , you do nothing here, but that is not security J

           }

           //更多安全检测实现

      //……

}

然后在程序中这样用:

System.setSecurityManager(new RMISecurityManager());

修改jdkpolicy:

$java.home/jre/lib/security/java.policyjdk默认的运行期安全检测定义在此处。具体如何修改可以去查jdk document.

4       rmi 中实现回调 (callback).

       首先定义一个回调接口Callback并实现它。在RMI服务中,定义一个注册方法,注册该Callback接口。从图形中可以看到我们用了一个registry(in cb:Callback):int 注册了一个Callback。然后就可以在服务器端进行回调接口中的方法调用了。在服务器端,我们看到,在实现接口中,定义了一个Callback callback的变量。此处,也许你需要定义一个List,然后把callback封装在这个List中,所有的客户端中的callback就可以放在list中了,这样在服务器端可以实现一个组播功能。当然,这只是从上面的UML图可以扩展的。

       rmi中,如果要实现回调功能,只能通过接口的方式实现,没有其他方法可以做到。(c中,是用函数指针实现回调功能)

 

水平有限,错误之处难免,如发现有不妥之处,务必告之,不胜感谢。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值