`

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  
  

相关推荐

    jdk1.6解压版本

    在JDK中,一些服务如RMI(Remote Method Invocation)、JMX(Java Management Extensions)、JDBC(Java Database Connectivity)等可能使用预设的端口号。在多Java应用运行的环境中,为了避免端口冲突,我们需要...

    jdk1.6源码包

    在JDK 1.6中,此文件夹可能包含了Oracle提供的各种服务和组件,如Java EE相关的库,或者与Java RMI(远程方法调用)和JMS(Java消息服务)相关的实现。 **4. launcher 文件夹** launcher目录包含了Java应用程序启动...

    JDK 1.6 API文档 中文版

    **JDK 1.6 API文档是Java开发者的重要参考资料,它包含了Java开发工具包1.6版本中的所有公共类、接口、方法和异常等详细信息。API(Application Programming Interface)文档是程序员理解和使用Java库的关键资源,它...

    java jdk 1.6 src.zip 源码

    Java JDK 1.6 是Java开发工具包的一个版本,它包含了编译器、JVM(Java虚拟机)、类库和其他工具,是Java开发者必备的基础环境。`src.zip` 文件是这个版本中的源代码压缩包,提供了Java核心库的源代码,使得开发者...

    jdk1.6API帮助文档

    总结来说,JDK 1.6 API帮助文档是Java开发者的重要参考资料,它覆盖了Java平台的核心功能和特性,无论对于初学者还是经验丰富的开发者,都是不可或缺的学习和调试工具。通过深入研究这些API,开发者可以更好地理解和...

    最实用的JDK1.6API

    除了这些,JDK1.6 API文档还包含许多其他功能,如XML解析、数据库连接(JDBC)、JavaMail、Java RMI等。开发者可以通过查阅这个中文文档,快速定位到所需的方法和类,提高开发效率,避免错误。《最实用的JDK1.6 API...

    JDK_API_1.6.zip

    《JavaTM Platform Standard Edition 6 API 规范》是中国官方发布的JDK 1.6版本的API文档,它是Java开发者的重要参考资料。这份文档详细阐述了Java SE 6平台的类库,包括各种类、接口、枚举和注解,涵盖了Java语言的...

    java jdk-api-1.6 中文 chmd

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

    JDK-API-1-6-zh-CN.CHM

    《JDK API 1.6 中文版》是Java开发者必备的参考资料,它详细记录了Java Development Kit(JDK)1.6版本中的各种类库、接口和方法,为编程工作提供了全面的API文档。CHM(Compiled HTML Help)格式的文件便于离线查阅...

    rmi 聊天室

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

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

    本示例将深入探讨JDK原生的RMI实现及其应用场景。** 首先,了解RMI的基本概念: 1. **远程接口(Remote Interface)**:这是定义远程方法的接口,必须继承`java.rmi.Remote`。每个远程方法都可能抛出`java.rmi....

    JDK5新版RMI编程指南

    ### JDK5新版RMI编程指南 #### RMI简介与发展历程 RMI(Remote Method Invocation),即远程方法调用,是一种允许在不同的Java虚拟机(JVM)之间进行远程调用的技术。它是Java平台上最早的远程访问技术之一,为...

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

    本篇将深入探讨如何利用JDK 1.5版本搭建一个基本的分布式Java RMI程序。RMI是Java在分布式计算领域的重要工具,它简化了网络应用的开发,使得开发者可以像操作本地对象一样操作远程对象。 首先,我们需要了解RMI的...

    RMI反序列化及相关工具反制浅析1

    对于开发和运维人员来说,定期更新JDK至最新安全版本,了解并利用像ysoserial这样的工具进行安全性测试,同时熟练掌握RMI的调试技巧,都是防范这类攻击的有效手段。同时,应强化Server端的输入验证,避免对未经验证...

    RMI入门(二)实例 --- 亲自将代码调试成功

    在本文中,我们将深入探讨Java Remote Method Invocation (RMI)技术,通过一个具体的实例来学习如何设置、构建和调试RMI应用。RMI是Java提供的一种远程对象调用机制,它允许Java对象在不同的JVM之间进行通信。在这个...

    JAVA_API1.6文档(中文)

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

    Rmi示例 Rmi代码示例

    以下是对这两个文件及其涉及的知识点的详细解释: 1. **RMI服务端**(RmiServer): - **接口定义**:RMI服务通常基于接口实现,服务器端会提供一个实现了特定接口的远程对象。这个接口定义了客户端可以调用的远程...

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

    - **调试困难**:远程方法调用的错误定位比本地方法调用更复杂。 总的来说,Java RMI是一种强大的工具,适合于构建内部Java企业级应用。然而,在需要跨语言交互或者高度安全性的场景下,可能需要考虑其他技术,如...

    JDK17-Linux-Arm64

    JDK是Java编程语言的核心工具集,它提供了编译、调试和运行Java应用程序所需的所有组件。在Linux Arm64平台上,JDK17为开发人员提供了在64位ARM处理器上构建和执行Java应用的能力,这在如今的服务器硬件和嵌入式设备...

    [Java参考文档].JDK_API 1.6

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

Global site tag (gtag.js) - Google Analytics