`
xumingming64398966@yahoo.com.cn
  • 浏览: 41092 次
文章分类
社区版块
存档分类

Java RPC通信机制之RMI

阅读更多

以下文字摘自:http://blog.csdn.net/billdavid/archive/2006/08/18/1095706.aspx


大卫注1<o:p></o:p>

写完CORBA系列后,本想接着写写其它几种典型的远程通信协议:RMIXML-RPCSOAP,但由于工作的原因,加之房子装修等麻烦事,一直没有心情动笔。今天接到装修公司老板电话说开工证要晚几天办下来,要停工4-5天,狂怒后突然有了静下心来完成原本想写的东西的想法,既来之,则安之(i.e.郁闷啊,郁闷啊,就习惯了...<o:p></o:p>

大卫注2<o:p></o:p>

这个系列基本上是一份笔记,没有加入太多我自己的东西,仅仅记录了自己在使用过程中遇到的问题,及其解决办法。<o:p></o:p>

 <o:p></o:p>

在传统的RPC编程接口逐渐淡出人们视线的同时,新的、更便于使用且附加了更多特性的RPC编程接口也不断涌现,CORBA作为分布式对象计算技术的典范,在很长一段时间内极大地吸引了大家的注意,但是由于CORBA规范试图覆盖过多的内容,使得CORBA显得过于复杂,也极大地限制了CORBA的应用范围,本系列将向大家介绍几种轻量级的,更适于在Java开发中使用的RPC编程接口:RMIXML-RPCSOAP<o:p></o:p>

RMIRemote Method Invocation

与本系列将介绍的其它两种RPC编程接口不同,RMIRemote Method Invocation)显得有些老旧,它是在Java-IDL加入J2SE之前被引入的。RMI开发流程与CORBA如出一辙(从出现的时间上无法确定RMI是否是按照CORBA规范定制的),因此,其开发过程相对比较烦琐,但是由于RMIEJB的基础,因此,它在Java开发中具有十分重要的地位。<o:p></o:p>

以下是创建远程方法调用的5个步骤:<o:p></o:p>

1.   定义一个扩展了Remote接口的接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常;<o:p></o:p>

2.   定义一个实现该接口的类;<o:p></o:p>

3.   使用rmic程序生成远程实现所需的存根和框架;<o:p></o:p>

4.   创建一个客户程序和服务器进行RMI调用;<o:p></o:p>

5.   启动rmiregistry并运行自己的服务程序和客户程序。<o:p></o:p>

下面举一个简单、而且被无数次引用的例子:Echo<o:p></o:p>

1、定义Echo接口

//Echo.java<o:p></o:p>

//The Echo remote interface<o:p></o:p>

package demo.rmi;<o:p></o:p>

 <o:p></o:p>

import java.rmi.*;<o:p></o:p>

 <o:p></o:p>

public interface Echo extends Remote {<o:p></o:p>

      String echo(String msg) throws RemoteException;<o:p></o:p>

}<o:p></o:p>

2、实现Echo接口

//EchoServer.java<o:p></o:p>

//The implementation of the Echo remote object<o:p></o:p>

package demo.rmi;<o:p></o:p>

 <o:p></o:p>

import java.net.*;<o:p></o:p>

import java.rmi.*;<o:p></o:p>

import java.rmi.registry.*;<o:p></o:p>

import java.rmi.server.*;<o:p></o:p>

 <o:p></o:p>

public class EchoServer<o:p></o:p>

      extends UnicastRemoteObject<o:p></o:p>

      implements Echo {<o:p></o:p>

       //默认构件器,也要“掷”出RemoteException违例<o:p></o:p>

      public EchoServer() throws RemoteException {<o:p></o:p>

            super();<o:p></o:p>

      }<o:p></o:p>

 <o:p></o:p>

      public String echo(String msg) throws RemoteException {<o:p></o:p>

            return "Echo: " + msg;<o:p></o:p>

      }<o:p></o:p>

 <o:p></o:p>

      public static void main(String [] args) {<o:p></o:p>

            /*创建和安装一个安全管理器,令其支持RMI作为Java开发包的一部分,适用于RMI唯一一个是RMISecurityManager.*/<o:p></o:p>

            System.setSecurityManager(new RMISecurityManager());<o:p></o:p>

 <o:p></o:p>

            try {<o:p></o:p>

                     /*创建远程对象的一个或多个实例,下面是EchoServer对象*/<o:p></o:p>

                  EchoServer es = new EchoServer();<o:p></o:p>

                  /*向RMI远程对象注册表注册至少一个远程对象。一个远程对象拥有的方法即可生成指向其他远程对象的句柄,这样,客户到注册表里访问一次,得到第一个远程对象即可.*/<o:p></o:p>

                  Naming.rebind("EchoServer", es);<o:p></o:p>

                  System.out.println("Ready to provide echo service...");<o:p></o:p>

            } catch (Exception e) {<o:p></o:p>

                  e.printStackTrace();<o:p></o:p>

            }<o:p></o:p>

      }<o:p></o:p>

}<o:p></o:p>

这个实现类使用了UnicastRemoteObject去连接RMI系统。在我们的例子中,我们是直接的从UnicastRemoteObject这个类上继承的,事实上并不一定要这样做,如果一个类不是从UnicastRmeoteObject上继承,那必须使用它的exportObject()方法去连接到RMI。(否则,运行时将被告知无法序列化。)<o:p></o:p>

如果一个类继承自UnicastRemoteObject,那么它必须提供一个构造函数并且声明抛出一个RemoteException对象(否则,会遇到编译错误)。当这个构造函数调用了super(),它就激活UnicastRemoteObject中的代码完成RMI的连接和远程对象的初始化。<o:p></o:p>

3、运行rmic编译实现类,产生_Stub

demo.rmi.EchoServer.java上级目录下运行如下命令:<o:p></o:p>

rmic demo.rmi.EchoServer<o:p></o:p>

4、编写客户程序

//EchoClient.java<o:p></o:p>

//Uses remote object EchoServer<o:p></o:p>

package demo.rmi;<o:p></o:p>

 <o:p></o:p>

import java.rmi.*;<o:p></o:p>

import java.rmi.registry.*;<o:p></o:p>

 <o:p></o:p>

public class EchoClient {<o:p></o:p>

      public static void main(String [] args) {<o:p></o:p>

            System.setSecurityManager(new RMISecurityManager());<o:p></o:p>

 <o:p></o:p>

            try {<o:p></o:p>

                  Echo t = (Echo)Naming.lookup("EchoServer");<o:p></o:p>

 <o:p></o:p>

                  for (int i = 0; i < 10; i++) {<o:p></o:p>

                        System.out.println(t.echo(String.valueOf(i)));<o:p></o:p>

                  }<o:p></o:p>

            } catch (Exception e) {<o:p></o:p>

                  e.printStackTrace();<o:p></o:p>

            }<o:p></o:p>

      }<o:p></o:p>

}<o:p></o:p>

5、运行

编码的工作就只有这些,现在可以依次启动rmiregistry(启动rmiregistry时可以附加一个端口,一般使用默认的端口1099即可,这是默认的Naming Service运行端口)、EchoServerEchoClient了。但是,虽然有些RMI的资料没有提到,但你运行时不可避免会遇到如下两个错误:<o:p></o:p>

1java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:1099 connect,resolve)<o:p></o:p>

原因很简单,RMI Server/Client程序试图通过Socket连接访问本机的rmiregistry服务(即RMINaming Service,其运行的默认端口是1099)。要解决这个问题,可以在运行Server/Client时指定一个Policy文件(关于Policy的更多信息,见参考2),如下:<o:p></o:p>

java -Djava.security.policy=demo/rmi/policyfile.txt demo.rmi.EchoServer<o:p></o:p>

Policy文件的内容为:<o:p></o:p>

grant{<o:p></o:p>

      permission java.net.SocketPermission "localhost:1099", "connect, resolve";<o:p></o:p>

};<o:p></o:p>

即允许访问本机的1099端口。<o:p></o:p>

或者干脆来个彻底开放:<o:p></o:p>

grant {<o:p></o:p>

      permission java.security.AllPermission "", "";<o:p></o:p>

};<o:p></o:p>

2java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:<o:p></o:p>

        java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:<o:p></o:p>

        java.lang.ClassNotFoundException: demo.rmi.EchoServer_Stub<o:p></o:p>

        ...<o:p></o:p>

如果你凑巧用启动rmiregistry的终端窗口启动了EchoServer,那么你很走运,你看不到上面的错误,但如果你不是在看完这篇文章后就再也用不到RMI,那么,这个错误在那里等着你,:)<o:p></o:p>

错误很明显,rmiregistry找不到与EchoServer放在同一目录下的EchoServer_Stub,因为package所在demo.rmi目录的上级目录不在rmiregistryclasspath中,这个问题有两种解决方案:<o:p></o:p>

a)在启动rmiregistry前先调整一下CLASSPATH环境变量,以目录E:\为例,执行:<o:p></o:p>

set CLASSPATH=%CLASSPATH%;E:\<o:p></o:p>

b)修改code,在EchoServer中通过如下代码:<o:p></o:p>

Registry r = LocateRegistry.createRegistry(8111);<o:p></o:p>

r.rebind("EchoServer", es);<o:p></o:p>

在程序内部创建一个LocateRegistry,并将自身注册到该LocateRegistry,其中的数值8111表示LocateRegistry运行的端口。<o:p></o:p>

同样,对于客户程序,也需要作相应的调整:<o:p></o:p>

Registry r = LocateRegistry.getRegistry("localhost", 8111);<o:p></o:p>

Echo e = (Echo)r.lookup("EchoServer");<o:p></o:p>

而不是像上面例子中一样访问Naming类的static方法来访问默认的rmiregistry服务。<o:p></o:p>

参考:

1.      Java RMI Tutorial, http://www.ccs.neu.edu/home/kenb/com3337/rmi_tut.html<o:p></o:p>

2.      Policy Tool - Policy File Creation and Management Tool. http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/policytool.html<o:p></o:p>

3.     Java RMI入门实战,http://www.huihoo.com/java/rmi/index.html

分享到:
评论

相关推荐

    RPC通信模型(java)

    在Java中实现RPC通信模型,通常涉及客户端、服务端、序列化和网络通信等多个环节。以下是对这个主题的详细阐述: 1. **RPC基本原理**: RPC使得客户端可以像调用本地方法一样调用远程服务器上的方法,隐藏了网络...

    dubbo_rpc_hession_rmi

    RPC(Remote Procedure Call)是分布式系统中的一种基础通信机制,允许程序调用远程计算机上的函数或方法,就像调用本地函数一样。在“rpc的demo”中,我们将探讨RPC的基本原理和实现,理解如何通过RPC框架实现服务...

    java rmi 参考文档

    Java RMI(Remote Method Invocation)是一种允许调用不同Java虚拟机(JVM)上方法的机制。这些JVM可能位于不同的机器上,也可能在同一台机器上。无论哪种情况,被调用的方法都在与调用过程不同的地址空间中运行。 ...

    dubbo_ demo、角色_ RPC_原理 _RMI .zip

    RMI(Remote Method Invocation)是Java平台上的RPC实现,它允许Java对象在不同的JVM之间进行方法调用。RMI原理包括以下关键部分: 1. **接口定义**:服务提供者和消费者共享相同的接口定义,确保调用的一致性。 2....

    RMI.zip_Java RMI_RMI java_rmi

    不过,需要注意的是,随着Java技术的发展,例如Java EE和Web服务的出现,RMI在某些场景下可能已经被更现代的技术替代,如JAX-RPC和Web服务(SOAP/REST)。尽管如此,RMI仍然是理解分布式计算和Java平台核心特性的...

    分布式环境下Java RMI与RPC,JMS,CORBA,DCOM的比较

    ### 分布式环境下Java RMI与RPC,JMS,CORBA,DCOM的比较 在分布式计算领域,各种远程通信协议和技术被广泛采用以实现不同系统间的交互与数据共享。本文将详细介绍Java RMI(Remote Method Invocation)、RPC...

    RPC_RMI.zip_rpc

    RMI提供了序列化机制,使得Java对象能够在网络中传递。客户端和服务器之间使用Java接口进行通信,这样可以确保双方都知道如何相互交互。 RMI的核心组件包括: 1. **远程接口(Remote Interface)**:定义了客户端...

    javaRMI完整版.pdf

    Java Remote Method Invocation (RMI) 是Java平台上的一个重要特性,用于实现分布式对象之间的通信。RMI允许程序员在不同的Java虚拟机(JVM)之间调用方法,无论这些JVM位于同一台机器还是网络中的不同机器。这种技术...

    rmi和rpc Demo

    - **序列化**:RMI使用Java的序列化机制,RPC可以使用各种序列化格式,如JSON或protobuf。 - **安全性**:RMI默认不提供安全性,需要手动添加,而一些RPC框架(如gRPC)提供了内置的安全特性,如SSL/TLS。 ### ...

    java-RMI技术讲解

    相比于传统的RPC,RMI进一步简化了分布式对象之间的通信机制,使得开发者能够更加专注于业务逻辑而不用担心底层通信细节。 #### 2. RMI的用途 RMI主要用于分布式Java应用程序之间的远程通信。其核心优势在于: - ...

    RPC与RMI区别1

    相比之下,RMI是Java平台特有的技术,它只适用于Java环境。RMI基于TCP/IP协议,提供了对Java对象的远程调用能力。在RMI中,对象是可以被传输的,这得益于Java对象的序列化和反序列化机制。当使用RMI时,需要创建Stub...

    JAVA RPC框架简单开发实现

    总的来说,构建一个Java RPC框架涉及到多个技术点,包括服务接口定义、网络通信实现、心跳检测机制以及生产消费者模型的应用。通过这样的框架,可以实现分布式系统间的高效、可靠通信,同时提高系统的可扩展性和容错...

    RMI与RPC

    虽然RMI和RPC在概念上有相似之处,但它们在实现上存在一些关键区别: 1. **语言支持**:RPC是语言无关的,可以应用于各种编程语言,而RMI是Java平台专有的。 2. **对象传输**:RMI支持对象的传输,即调用结果可以...

    java_RPC_hadoop.zip

    通过模拟Hadoop的RPC通信,我们可以深入了解这些机制,并学习如何在Java中实现类似的远程通信方案,这对于开发分布式系统或理解Hadoop的工作原理具有重要意义。通过分析和实践,可以进一步优化通信效率,增强系统的...

    基于RPC方式的文件传输应用开发

    在RPC通信中,对象需要转换成字节流在网络上传输,到达目的地后再还原为对象。Java中的序列化API(java.io.Serializable)可以实现这一过程。或者,也可以使用如protobuf这样的高效序列化库。 七、异常处理 在...

    RPC-code_rpc_

    **RMI(Remote Method Invocation)** 是Java平台提供的一种原生的RPC机制。在RMI中,一个对象可以在不同的Java虚拟机之间进行透明调用,就像它们都在同一个JVM中一样。RMI包括了对象序列化和网络通信的细节,使得...

    distrubuted communications(RMI & RPC).pdf

    在IT领域,分布式通信是实现跨网络系统交互的关键技术之一,其中远程方法调用(RMI)和远程过程调用(RPC)是最为常见的两种机制。本文将深入探讨这两种技术的特点、工作原理以及它们之间的异同,以帮助程序员更好地...

Global site tag (gtag.js) - Google Analytics