`

RMI及其调试(JDK1.6)

    博客分类:
  • j2ee
阅读更多
一 RMI系统运行机理
    RMI应用程序通常包括两个独立的程序:服务器程序和客户机程序。典型的服务器应用程序将创建多个远程对象,使这些远程对象能够被引用,然后等待客户机调用这些远程对象的方法。而典型的客户机程序则从服务器中得到一个或多个远程对象的引用,然后调用远程对象的方法。RMI为服务器和客户机进行通信和信息传递提供了一种机制。
在与远程对象的通信过程中,RMI使用标准机制:stub和skeleton。远程对象的stub担当远程对象的客户本地代表或代理人角色。调用程序将调用本地stub的方法,而本地stub将负责执行对远程对象的方法调用。在RMI中,远程对象的stub与该远程对象所实现的远程接口集相同。调用 stub的方法时将执行下列操作:
(1) 初始化与包含远程对象的远程虚拟机的连接;
(2) 对远程虚拟机的参数进行编组(写入并传输);
(3) 等待方法调用结果;
(4) 解编(读取)返回值或返回的异常;
(5) 将值返回给调用程序。为了向调用程序展示比较简单的调用机制,stub将参数的序列化和网络级通信等细节隐藏了起来。在远程虚拟机中,每个远程对象都可以有相应的skeleton(在JDK1.2环境中无需使用skeleton)。Skeleton负责将调用分配给实际的远程对象实现。它在接收方法调用时执行下列操作:(1) 解编(读取)远程方法的参数;(2) 调用实际远程对象实现上的方法;(3) 将结果(返回值或异常)编组(写入并传输)给调用程序。stub和skeleton由rmic编译器生成。
    利用RMI编写分布式对象应用程序需要完成以下工作:(1) 定位远程对象。应用程序可使用两种机制中的一种得到对远程对象的引用。它既可用RMI的简单命名工具rmiregistry来注册它的远程对象,也可以将远程对象引用作为常规操作的一部分来进行传递和返回。(2)与远程对象通信。远程对象间通信的细节由RMI处理,对于程序员来说,远程通信看起来就像标准的Java方法调用。(3)给作为参数或返回值传递的对象加载类字节码。因为RMI允许调用程序将纯Java对象传给远程对象,所以,RMI将提供必要的机制,既可以加载对象的代码又可以传输对象的数据。在RMI分布式应用程序运行时,服务器调用注册服务程序以使名字与远程对象相关联。客户机在服务器上的注册服务程序中用远程对象的名字查找该远程对象,然后调用它的方法。
二 远程接口概念:
    RMI对接口有着强烈的依赖。在需要创建一个远程对象的时候,我们通过传递一个接口来隐藏基层的实施细节。所以客户得到远程对象的一个句柄正好同一些本地的根代码连接,有后者负责通过网络通信。但我们并不关心这些事情,通过自己的接口句柄发送消息即可。
创建一个远程接口时,必须遵守下列规则:
1)  远程接口必须为public属性(不能有“包访问”;也就是说,他不能是“友好的”)。否则,一旦客户试图装载一个实现了远程接口的远程对象,就会得到一个错误。
2)  远程接口必须扩展接口java.rmi.Remote。
3)  除与应用程序本身有关的违例,远程接口中的每个方法都必须在自己的throws从句中声明java.rmi.RemoteException.
4)  作为参数或返回值传递的一个远程对象(不管是直接,还是本地对象中嵌入)必须声明为远程接口,不可声明为实施类。
三 远程接口的实施:
    服务器必须包含一个扩展了UnicastRemoteObject类,并实现远程接口。这个类也可以含有附加的方法,但客户只能使用远程接口中的方法。因为客户是指向接口的一个句柄,而不是它的哪个类。
必须为远程对象定义构造方法,即使只准备定义一个默认构造方法,用它调用基础类构造方法。必须把它明确地编写出来,因为它必须“掷”出RemoteException违例。
四 代码存根:
    当客户代码调用一个远程对象上的远程方法是,实际上是调用一个Java编程语言的普通方法,这个方法是封装在stub(代码存根)的代用对象。存根(Stub)是远程对象在客户端的代理,它将RMI调用传递给服务器端的骨架(Skeleton),后者负责将该调用传递给实际的远程方法。
    要完成这个工作可使用rmic编译器,rmic编译器生成远程对象的存根和骨架。
    代码存根在服务器端创建,必须驻留于客户端。
五 RMI实战
一个正常工作的RMI系统由下面几个部分组成:
● 远程服务接口的定义
● 远程服务接口的具体实现
● 桩(Stub)和框架(Skeleton)文件
● 一个运行远程服务的服务器
● 一个RMI命名服务,它允许客户端去发现这个远程服务
● 类文件的提供者(一个HTTP或者FTP服务器)
● 一个需要这个远程服务的客户端程序
如果所有的RMI文件都已经设计好了,那么需要下面的几个步骤去生成系统:
1、  编写并且编译接口的Java代码
2、  编写并且编译接口实现的Java代码
3、  从接口实现类中生成桩(Stub)和框架(Skeleton)类文件
4、  编写远程服务的主运行程序
5、  编写RMI的客户端程序
6、  安装并且运行RMI系统
实现过程如下:(以下代码在Windows Server 2003,JDK1.6环境下调试通过,代码来自互联网)
服务器端:
1接口
第一步就是建立和编译服务接口的Java代码。这个接口定义了所有的提供远程服务的功能,下面是源程序:
Product,java
import java.rmi.*;
public interface Product extends  Remote
{
    String getDescription() throws RemoteException;
}
2接口的具体实现
下一步,我们就要写远程服务的具体实现,这是一个ProductImpl类文件:
ProductImpl.java
import java.rmi.*;
import java.rmi.server.*;
public class ProductImpl extends UnicastRemoteObject implements Product
{
    private String name ;
    public ProductImpl(String n) throws RemoteException
    {
       name = n;
    }
    public String getDescription()
    {
         return "Hello,I am " + name + " . I love you !";
    }     
}
3 桩(Stubs)和框架(Skeletons)
  下一步就是要使用RMI编译器rmic来生成桩和框架文件,这个编译运行在远程服务实现类文件上。
>rmic ProductImpl
在你的目录下运行上面的命令,成功执行完上面的命令你可以发现一个ProductImpl_stub.class文件,如果你是使用的是1.2以前的SDK,那么你还可以发现ProductImpl_Skel.class文件。
4 主机服务器
远程RMI服务必须是在一个服务器中运行的。
ProductServer.java
import java.rmi.*;
import java.rmi.server.*;
public class ProductServer {
public static void main(String args[])
    {
        try
        {
            System.out.println("Construction server implementats ...");
            ProductImpl p1 = new ProductImpl("Wang.yuanbin");
            ProductImpl p2 = new ProductImpl("Bueaty");
            System.out.println("binding server implementation to registry ...");
            Naming.rebind("wyb",p1);
            Naming.rebind("Beau",p2);
            System.out.println("Waiting for invocations from clients ...");
        }
        catch (Exception ex)
        {
            System.out.println("Error: " + ex );
        }
    }

}

5  客户端
ProductClient.java
import java.rmi.*;
import java.rmi.server.*;
public class ProductClient
{
    public static void main(String [] args)
    {
        System.setSecurityManager(new RMISecurityManager());
        String url = "rmi://localhost/";
        try
        {
            Product c1 = (Product) Naming.lookup(url + "wyb");
            Product c2 = (Product) Naming.lookup(url + "Beau");
            System.out.println(c1.getDescription());
            System.out.println(c2.getDescription());
        }
        catch (Exception ex)
        {
            System.out.println("Error : " + ex);
        }
        System.exit(0);
    }
}
在该类中使用java.rmi.Naming中的lookup()方法获得对远程对象的引用,依据需要调用该引用的远程方法,其调用方式和对本地对象方法的调用相同。.
6 安全策略文件
因为RMI的安全机制将在服务端发生作用,所以你必须增加一条安全策略。以下是对应安全策略的例子。
ProductServer.policy和ProductClient.policy
grant {
permission java.security.AllPermission "", "";
};
注意:这是一条最简单的安全策略,它允许任何人做任何事,对于你的更加关键性的应用,你必须指定更加详细安全策略。
如果没有上面的安全策略,运行客户端时,会出现如下错误:

E:\wx\2>java ProductClient
Error : java.security.AccessControlException: access denied (java.net.SocketPerm
ission 127.0.0.1:1099 connect,resolve)

7 运行RMI系统

按如下步骤编译、运行系统:

1)为接口、实现和客户、服务器类编译源文件:
Javac Product*.java
2)在实现类上运行rmic
Rmic ProductImpl
3)启动rmi注册程序
Start rmiregistry
4)  启动服务器
start java  -Djava.security.policy=ProductServer.policy ProductServer
如果不指定安全策略,服务器将无法提供服务,一运行即关闭;指定安全策略后,运行后显示:
Construction server implementats ...
binding server implementation to registry ...
Waiting for invocations from clients ...
5)  运行客户程序
Java –Djava.security.policy=ProductClient.policy ProductClient
运行后屏幕显示如下:
E:\wx\2>java  -Djava.security.policy=ProductClient.policy ProductClient
Hello,I am Wang.yuanbin . I love you !
Hello,I am Bueaty . I love you !

E:\wx\2>

8 错误分析:(以下代码同样来自互联网,但未调试通过)
  在我测试RMI的过程中,曾经出现如下错误,但未找出原因:
   E:\wx>java -Djava.security.policy=RmiHelloClient.policy RmiHelloClient
java.rmi.ConnectException: Connection refused to host: localhost; nested excepti
on is:
        java.net.ConnectException: Connection refused: connect
        at sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)
        at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
        at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
        at sun.rmi.server.UnicastRef.newCall(Unknown Source)
        at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
        at java.rmi.Naming.lookup(Unknown Source)
        at RmiHelloClient.main(RmiHelloClient.java:19)
Caused by: java.net.ConnectException: Connection refused: connect
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.PlainSocketImpl.doConnect(Unknown Source)
        at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
        at java.net.PlainSocketImpl.connect(Unknown Source)
        at java.net.SocksSocketImpl.connect(Unknown Source)
        at java.net.Socket.connect(Unknown Source)
        at java.net.Socket.connect(Unknown Source)
        at java.net.Socket.<init>(Unknown Source)
        at java.net.Socket.<init>(Unknown Source)
        at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(Unknown S
ource)
        at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(Unknown S
ource)
        ... 7 more
出错的代码如下:
   远程接口
   import java.rmi.*;

    public interface RmiHelloRemoteIntfc extends Remote
    {
      String helloRemoteObj(String client) throws RemoteException;
    }
    远程接口实现
    import java.rmi.server.*;
    import java.rmi.*;
    public class RmiHelloRemoteObj extends UnicastRemoteObject implements RmiHelloRemoteIntfc
    {
      public RmiHelloRemoteObj() throws RemoteException
    {
      super();
     }
     public String helloRemoteObj(String client) throws RemoteException
     {
       return "Hello World"+client;
     }
     }
     服务器
     import java.io.*;
     import java.rmi.*;
     import java.rmi.server.*;
     import sun.applet.*;
     import java.rmi.registry.LocateRegistry;

     public class RmiHelloServer
     {

      public RmiHelloServer()
      {
      }
      public static void main(String[] args)
      {
       //创建并安装安全管理器
       if(System.getSecurityManager()==null)
       {
         System.setSecurityManager(new RMISecurityManager());
       }

       try{
         //创建远程对象
         RmiHelloRemoteObj ttt=new RmiHelloRemoteObj();
         //启动注册表
         LocateRegistry.createRegistry(4588);
         //奖名称绑定到对象
         //System.setProperty("java.rmi.server.localhost","211.81.207.109");
         Naming.rebind("//localhost/wx",ttt);

         System.out.println("RMI服务器正在运行。。。。。。");
      }
      catch(Exception e)
      {
         e.printStackTrace();
      }
      }
      }
      客户端
      import java.rmi.*;
      import java.rmi.server.*;

      public class RmiHelloClient
      {

       public RmiHelloClient()
      {
      }
      public static void main(String[] args)
      {
      //创建并安装安全管理器
      if(System.getSecurityManager()==null)
     {
       System.setSecurityManager(new RMISecurityManager());
     }

      try{
           RmiHelloRemoteIntfc c1=(RmiHelloRemoteIntfc)Naming.lookup("rmi://localhost/wx");
           System.out.println(c1.helloRemoteObj("Everyone"));
      }
      catch(Exception e)
      {
         e.printStackTrace();
       }
      System.exit(0);
       }
      }
      策略文件
    
       grant codeBase
       "file:/e:/wx/"
       {
        //  permission java.net.SocketPermission
         // "*:1000-65535","accept,connect,listen,resolve";
         permission java.security.AllPermission "", "";
       };

分享到:
评论
1 楼 Caelebs 2017-09-27  
  

相关推荐

    java jdk-api-1.6 中文 chmd

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax...

    JDK5新版RMI编程指南

    JDK5中,RMI技术已经得到了重大更新。现在使用JDK提供的RMI类,可以相当简单的发布RMI服务! 在JDK5发布之前,使用RMI是一件非常繁琐的事情。甚至很多程序员把EJB当作对RMI的封装,当作RMI的简化版! 而今,RMI已经...

    jdk-rmi:jdk原生rmi应用示例

    jdk-rmi jdk原生rmi应用示例

    rmi 聊天室

    rmi 聊天室 自己改下批处理文件路径就可以运行啦,jdk1.6编译的,源码在src里,课程作业,供大家参考

    jdk自带工具说明

    1.5、Java IDL and RMI-IIOP 工具 3 1.6、Java 部署工具 4 1.7、Java 插件工具 4 1.8、Java web 启动工具 4 1.9、Java 故障检修,程序概要分析,监视和管理工具 4 1.10、Java web 服务工具 4 1.11、监视工具 4 1.12...

    [Java参考文档].JDK_API 1.6

    javax.xml.bind.annotation.adapters XmlAdapter 及其规范定义的子类允许任意 Java 类与 JAXB 一起使用。 javax.xml.bind.attachment 此包由基于 MIME 的包处理器实现,该处理器能够解释并创建基于 MIME 的包格式的...

    java rmi java rmi

    java rmi java rmijava rmi javajava rmi java rmi rmi

    RMI简单实例RMI简单实例

    RMI简单实例RMI简单实例RMI简单实例

    RMI技术研究及其在EJB中的应用

    分布式对象; 远程方法调用; CORBA; RMI-IIOP; 企业JavaBeans RMI技术研究及其在EJB中的应用

    JAVA_API1.6文档(中文)

    javax.xml.bind.annotation.adapters XmlAdapter 及其规范定义的子类允许任意 Java 类与 JAXB 一起使用。 javax.xml.bind.attachment 此包由基于 MIME 的包处理器实现,该处理器能够解释并创建基于 MIME 的包格式的...

    Java 1.6 API 中文 New

    Java 1.6 API的中文帮助文档。 深圳电信培训中心徐海蛟博士教学用api中文文档。支持全文检索,在线即时查询。 里面列出了,Java的所有类及其使用方法! Java SE Platform 软件包: java.applet 提供创建 applet 所...

    rmi技术客户端调用服务器的函数解决问题

    我一脸懵逼,不要配置环境,jar又放不进去,eclipse又不是神仙,那怎么跑的了rmi,最后经过激烈讨论,得到结果jdk版本过低,两天配不了的情况原因也是rmi是很久以前的技术,对应的文件名字和网站以及eclispe都有大量...

    Rmi示例 Rmi代码示例

    完整的Rmi调用示例,极难得的Rmi应用示例

    java RMI 详解,实例加原理,想不理解都难

    这是java RMI 详解,通过例子加原理的解说,分步骤,通过简单的代码行行解释,看完想不会都难

    rmi的实例rmi的实例rmi的实例

    rmi的详细例子,rmi的详细用法,一看就懂

    jdk-9.0.1_doc-all 最新版

    jdk.naming.rmi Provides the implementation of the RMI Java Naming provider. jdk.net Defines the JDK-specific Networking API. jdk.pack Defines tools for transforming a JAR file into a compressed ...

    RMI网络编程开发之二 如何搭建基于JDK1.5的分布式JAVA RMI 程序

    NULL 博文链接:https://javasam.iteye.com/blog/1848846

    RMI规范 RMI详细介绍

    RMI 规范 RMI 详细介绍 共10章

    RMI教程-入门经典

    RMI教程 Java RMIRMI教程 Java RMIRMI教程 Java RMIRMI教程 Java RMIRMI教程 Java RMI

    RMI远程方法调用RMI远程方法调用

    RMI远程方法调用RMI远程方法调用RMI远程方法调用RMI远程方法调用RMI远程方法调用

Global site tag (gtag.js) - Google Analytics