`
美丽的小岛
  • 浏览: 309443 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

<转>网络编程RMI

阅读更多

转自:http://hi.baidu.com/sham_rock/blog/item/a04ab52d53e5ad37349bf783.html

15.8 远程方法
为通过网络执行其他机器上的代码,传统的方法不仅难以学习和掌握,也极易出错。思考这个问题最佳的方式是:某些对象正好位于另一台机器,我们可向它们发送一条消息,并获得返回结果,就象那些对象位于自己的本地机器一样。Java 1.1的“远程方法调用”(RMI)采用的正是这种抽象。本节将引导大家经历一些必要的步骤,创建自己的RMI对象。

15.8.1 远程接口概念
RMI对接口有着强烈的依赖。在需要创建一个远程对象的时候,我们通过传递一个接口来隐藏基层的实施细节。所以客户得到远程对象的一个句柄时,它们真正得到的是接口句柄。这个句柄正好同一些本地的根代码连接,由后者负责通过网络通信。但我们并不关心这些事情,只需通过自己的接口句柄发送消息即可。
创建一个远程接口时,必须遵守下列规则:
(1) 远程接口必须为public属性(不能有“包访问”;也就是说,它不能是“友好的”)。否则,一旦客户试图装载一个实现了远程接口的远程对象,就会得到一个错误。
(2) 远程接口必须扩展接口java.rmi.Remote。
(3) 除与应用程序本身有关的违例之外,远程接口中的每个方法都必须在自己的throws从句中声明java.rmi.RemoteException。
(4) 作为参数或返回值传递的一个远程对象(不管是直接的,还是在本地对象中嵌入)必须声明为远程接口,不可声明为实施类。

下面是一个简单的远程接口示例,它代表的是一个精确计时服务:
//: PerfectTimeI.java
// The PerfectTime remote interface
package c15.ptime;
import java.rmi.*;

interface PerfectTimeI extends Remote {
  long getPerfectTime() throws RemoteException;
} ///:~

它表面上与其他接口是类似的,只是对Remote进行了扩展,而且它的所有方法都会“掷”出RemoteException(远程违例)。记住接口和它所有的方法都是public的。

15.8.2 远程接口的实施
服务器必须包含一个扩展了UnicastRemoteObject的类,并实现远程接口。这个类也可以含有附加的方法,但客户只能使用远程接口中的方法。这是显然的,因为客户得到的只是指向接口的一个句柄,而非实现它的那个类。
必须为远程对象明确定义构建器,即使只准备定义一个默认构建器,用它调用基础类构建器。必须把它明确地编写出来,因为它必须“掷”出RemoteException违例。
下面列出远程接口PerfectTime的实施过程:
//: PerfectTime.java
// The implementation of the PerfectTime
// remote object
package c15.ptime;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.net.*;

public class PerfectTime
    extends UnicastRemoteObject
    implements PerfectTimeI {
  // Implementation of the interface:
  public long getPerfectTime()
      throws RemoteException {
    return System.currentTimeMillis();
   }
  // Must implement constructor to throw
  // RemoteException:
  public PerfectTime() throws RemoteException {
    // super(); // Called automatically
   }
  // Registration for RMI serving:
  public static void main(String[] args) {
     System.setSecurityManager(
      new RMISecurityManager());
    try {
       PerfectTime pt = new PerfectTime();
       Naming.bind(
        "//colossus:2005/PerfectTime", pt);
       System.out.println("Ready to do time");
     } catch(Exception e) {
       e.printStackTrace();
     }
   }
} ///:~

在这里,main()控制着设置服务器的全部细节。保存RMI对象时,必须在程序的某个地方采取下述操作:
(1) 创建和安装一个安全管理器,令其支持RMI。作为Java发行包的一部分,适用于RMI唯一一个是RMISecurityManager。
(2) 创建远程对象的一个或多个实例。在这里,大家可看到创建的是PerfectTime对象。
(3) 向RMI远程对象注册表注册至少一个远程对象。一个远程对象拥有的方法可生成指向其他远程对象的句柄。这样一来,客户只需到注册表里访问一次,得到第一个远程对象即可。

1. 设置注册表
在这儿,大家可看到对静态方法Naming.bind()的一个调用。然而,这个调用要求注册表作为计算机上的一个独立进程运行。注册表服务器的名字是rmiregistry。在32位Windows环境中,可使用:
start rmiregistry
令其在后台运行。在Unix中,使用:
rmiregistry &
和许多网络程序一样,rmiregistry位于机器启动它所在的某个IP地址处,但它也必须监视一个端口。如果象上面那样调用rmiregistry,不使用参数,注册表的端口就会默认为1099。若希望它位于其他某个端口,只需在命令行添加一个参数,指定那个端口编号即可。对这个例子来说,端口将位于2005,所以rmiregistry应该象下面这样启动(对于32位Windows):
start rmiregistry 2005
对于Unix,则使用下述命令:
rmiregistry 2005 &
与端口有关的信息必须传送给bind()命令,同时传送的还有注册表所在的那台机器的IP地址。但假若我们想在本地测试RMI程序,就象本章的网络程序一直测试的那样,这样做就会带来问题。在JDK 1.1.1版本中,存在着下述两方面的问题(注释⑦):
(1) localhost不能随RMI工作。所以为了在单独一台机器上完成对RMI的测试,必须提供机器的名字。为了在32位Windows环境中调查自己机器的名字,可进入控制面板,选择“网络”,选择“标识”卡片,其中列出了计算机的名字。就我自己的情况来说,我的机器叫作“Colossus”(因为我用几个大容量的硬盘保存各种不同的开发系统——Clossus是“巨人”的意思)。似乎大写形式会被忽略。
(2) 除非计算机有一个活动的TCP/IP连接,否则RMI不能工作,即使所有组件都只需要在本地机器里互相通信。这意味着在试图运行程序之前,必须连接到自己的ISP(因特网服务提供者),否则会得到一些含义模糊的违例消息。

⑦:为找出这些信息,我不知损伤了多少个脑细胞。

考虑到这些因素,bind()命令变成了下面这个样子:
Naming.bind("//colossus:2005/PerfectTime", pt);
若使用默认端口1099,就没有必要指定一个端口,所以可以使用:
Naming.bind("//colossus/PerfectTime", pt);
在JDK未来的版本中(1.1之后),一旦改正了localhost的问题,就能正常地进行本地测试,去掉IP地址,只使用标识符:
Naming.bind("PerfectTime", pt);
服务名是任意的;它在这里正好为PerfectTime,和类名一样,但你可以根据情况任意修改。最重要的是确保它在注册表里是个独一无二的名字,以便客户正常地获取远程对象。若这个名字已在注册表里了,就会得到一个AlreadyBoundException违例。为防止这个问题,可考虑坚持使用rebind(),放弃bind()。这是由于rebind()要么会添加一个新条目,要么将同名的条目替换掉。
尽管main()退出,我们的对象已经创建并注册,所以会由注册表一直保持活动状态,等候客户到达并发出对它的请求。只要rmiregistry处于运行状态,而且我们没有为名字调用Naming.unbind()方法,对象就肯定位于那个地方。考虑到这个原因,在我们设计自己的代码时,需要先关闭rmiregistry,并在编译远程对象的一个新版本时重新启动它。
并不一定要将rmiregistry作为一个外部进程启动。若事前知道自己的是要求用以注册表的唯一一个应用,就可在程序内部启动它,使用下述代码:
LocateRegistry.createRegistry(2005);
和前面一样,2005代表我们在这个例子里选用的端口号。这等价于在命令行执行rmiregistry 2005。但在设计RMI代码时,这种做法往往显得更加方便,因为它取消了启动和中止注册表所需的额外步骤。一旦执行完这个代码,就可象以前一样使用Naming进行“绑定”——bind()。

15.8.3 创建根与干
若编译和运行PerfectTime.java,即使rmiregistry正确运行,它也无法工作。这是由于RMI的框架尚未就位。首先必须创建根和干,以便提供网络连接操作,并使我们将远程对象伪装成自己机器内的某个本地对象。
所有这些幕后的工作都是相当复杂的。我们从远程对象传入、传出的任何对象都必须“implement Serializable”(如果想传递远程引用,而非整个对象,对象的参数就可以“implement Remote”)。因此可以想象,当根和干通过网络“汇集”所有参数并返回结果的时候,会自动进行序列化以及数据的重新装配。幸运的是,我们根本没必要了解这些方面的任何细节,但根和干却是必须创建的。一个简单的过程如下:在编译好的代码中调用rmic,它会创建必需的一些文件。所以唯一要做的事情就是为编译过程新添一个步骤。
然而,rmic工具与特定的包和类路径有很大的关联。PerfectTime.java位于包c15.Ptime中,即使我们调用与PerfectTime.class同一目录内的rmic,rmic都无法找到文件。这是由于它搜索的是类路径。因此,我们必须同时指定类路径,就象下面这样:
rmic c15.PTime.PerfectTime
执行这个命令时,并不一定非要在包含了PerfectTime.class的目录中,但结果会置于当前目录。
若rmic成功运行,目录里就会多出两个新类:
PerfectTime_Stub.class
PerfectTime_Skel.class
它们分别对应根(Stub)和干(Skeleton)。现在,我们已准备好让服务器与客户互相沟通了。

15.8.4 使用远程对象
RMI全部的宗旨就是尽可能简化远程对象的使用。我们在客户程序中要做的唯一一件额外的事情就是查找并从服务器取回远程接口。自此以后,剩下的事情就是普通的Java编程:将消息发给对象。下面是使用PerfectTime的程序:
//: DisplayPerfectTime.java
// Uses remote object PerfectTime
package c15.ptime;
import java.rmi.*;
import java.rmi.registry.*;

public class DisplayPerfectTime {
  public static void main(String[] args) {
     System.setSecurityManager(
      new RMISecurityManager());
    try {
       PerfectTimeI t =
         (PerfectTimeI)Naming.lookup(
          "//colossus:2005/PerfectTime");
      for(int i = 0; i < 10; i++)
         System.out.println("Perfect time = " +
           t.getPerfectTime());
     } catch(Exception e) {
       e.printStackTrace();
     }
   }
} ///:~

ID字串与那个用Naming注册对象的那个字串是相同的,第一部分指出了URL和端口号。由于我们准备使用一个URL,所以也可以指定因特网上的一台机器。
从Naming.lookup()返回的必须造型到远程接口,而不是到类。若换用类,会得到一个违例提示。
在下述方法调用中:
t.getPerfectTime( )
我们可看到一旦获得远程对象的句柄,用它进行的编程与用本地对象的编程是非常相似(仅有一个区别:远程方法会“掷”出一个RemoteException违例)。

15.8.5 RMI的替选方案
RMI只是一种创建特殊对象的方式,它创建的对象可通过网络发布。它最大的优点就是提供了一种“纯Java”方案,但假如已经有许多用其他语言编写的代码,则RMI可能无法满足我们的要求。目前,两种最具竞争力的替选方案是微软的DCOM(根据微软的计划,它最终会移植到除Windows以外的其他平台)以及CORBA。CORBA自Java 1.1便开始支持,是一种全新设计的概念,面向跨平台应用。在由Orfali和Harkey编著的《Client/Server Programming with Java and CORBA》一书中(John Wiley&Sons 1997年出版),大家可获得对Java中的分布式对象的全面介绍(该书似乎对CORBA似乎有些偏见)。为CORBA赋予一个较公正的对待的一本书是由Andreas Vogel和Keith Duddy编写的《Java Programming with CORBA》,John Wiley&Sons于1997年出版。

分享到:
评论

相关推荐

    java应用软件程序设计

    114&lt;br&gt;实例39 读取配置文件 115&lt;br&gt;实例40 流操作 117&lt;br&gt;实例41 管道操作 118&lt;br&gt;实例42 标准I/O重定向 121&lt;br&gt;实例43 文件过滤器 122&lt;br&gt;实例44 获取文件信息 123&lt;br&gt;第4章 Java网络编程 125&lt;br&gt;实例45 选择字体 ...

    网络编程入门rmi初级教程

    本教程主要针对RMI的初级学习者,将引导你逐步进入这个激动人心的网络编程世界。 首先,让我们理解什么是RMI。RMI是Java的特性之一,它使得Java应用程序能够透明地调用远程对象的方法,就像调用本地对象一样。这种...

    超爽的自学课件(java)

    &lt;br&gt;&lt;br&gt;(15) 第15章 网络编程&lt;br&gt;开始编写网络应用时,就会发现所有Java特性和库仿佛早已串联到了一起。本章将探讨如何通过因特网通信,以及Java用以辅助此类编程的一些类。此外,这里也展示了如何创建一个Java程序...

    Spring RMI

    - **配置RMI服务**:在Spring的XML配置文件中,使用`&lt;bean&gt;`标签定义RMI服务,指定远程接口、实现类以及RMI服务的端口。 - **注册RMI服务**:使用`&lt;bean&gt;`标签的`lookup-by-name`属性,将服务注册到RMI注册表。 - **...

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

    RMI是Java在分布式计算领域的重要工具,它简化了网络应用的开发,使得开发者可以像操作本地对象一样操作远程对象。 首先,我们需要了解RMI的基本概念。RMI系统由两部分组成:服务器端(Server)和客户端(Client)...

    spring RMI 服务(自动把service发布为RMI服务)

    Spring RMI服务是一种在Java平台上实现远程方法调用(Remote Method Invocation, RMI)的技术,它允许分布式系统中的不同组件通过网络进行通信。在Spring框架的支持下,我们可以更方便地将服务发布为RMI服务,使得...

    spring RMI简单例子

    &lt;bean id="rmiServer" class="org.springframework.remoting.rmi.RmiServiceExporter"&gt; &lt;property name="registryPort" value="1099" /&gt; &lt;property name="service" ref="myRemoteService" /&gt; &lt;property name=...

    JavaRMI分布式编程心得

    ### Java RMI 分布式编程心得详解 #### 一、Java RMI 分布式编程概述 Java远程方法调用(Remote Method Invocation, RMI)是一种让位于不同Java虚拟机(Java Virtual Machine, JVM)上的对象能够互相调用彼此方法...

    liaotianshi.rar_RMI聊天室_java 网络_rmi _rmi 聊天_网络聊天室

    综上所述,"liaotianshi.rar_RMI聊天室_java 网络_rmi _rmi 聊天_网络聊天室"是一个使用Java RMI技术构建的网络聊天应用,涉及了Java网络编程、RMI原理及其应用,以及可能的并发处理和安全优化。通过对RMI的理解和...

    Java网络编程(第4版)PDF

    《Java网络编程(第4版)》是一本深入探讨Java平台上的网络编程技术的专业书籍,适合想要提升Java通讯技术的学者阅读。此书全面覆盖了Java网络编程的基础和高级概念,帮助开发者理解如何利用Java语言构建高效、可靠的...

    java RMI技术实现的网络聊天室

    10. **网络编程**:RMI涉及TCP/IP网络编程,客户端和服务器之间通过Socket进行通信。理解套接字编程的基本原理有助于深入理解RMI的工作机制。 以上是关于“java RMI技术实现的网络聊天室”的主要知识点。通过这个...

    (转)用c++实现java的rmi服务

    2. **网络通信**:C++标准库提供了`&lt;socket&gt;`头文件用于网络编程。我们需要建立客户端和服务器之间的TCP连接,以传输序列化后的数据。 3. **远程方法调用协议**:设计一套自定义的协议来表示方法名、参数和返回值。...

    (转)通用JAVA RMI服务器框架

    【标题】:“(转)通用JAVA RMI服务器框架” 【正文】: 在Java远程方法调用(Remote Method Invocation,RMI)技术中,构建一个通用的服务器框架是提高开发效率和代码可复用性的关键。Java RMI允许分布式计算,使得...

    西北工业大学软件学院网络与分布计算lab3_RMI.zip

    "西北工业大学软件学院网络与分布计算lab3_RMI.zip" 这个标题揭示了这个压缩包文件的来源和主题。它来源于西北工业大学的软件学院,是网络与分布计算课程的一个实验项目,重点是Remote Method Invocation(RMI)技术...

    分布式程序java 实验名称 基于Java RMI的C/S编程实验

    Socket是网络编程的基础,它允许两个网络应用之间进行双向通信。在Java中,`java.net.Socket` 和 `java.net.ServerSocket` 类用于创建客户端和服务器端的连接。客户端通过Socket连接到服务器,发送请求,然后服务器...

    RMI实现的网络五子棋

    【标题】"RMI实现的网络五子棋"是一个基于Java Remote Method Invocation (RMI)技术构建的在线游戏项目,允许玩家在两台计算机之间进行实时的五子棋对战。RMI是Java平台中用于分布式计算的重要工具,它允许对象在...

    Java RMI分布式编程实例

    在这个"Java RMI分布式编程实例"中,我们将深入探讨RMI的基本概念、工作原理以及如何通过实例来掌握其关键特性。 1. **RMI基本概念** - **远程接口(Remote Interface)**:定义了远程对象的方法签名,它是客户端...

    java网络编程

    java网络编程包括socket tcp/udp io/nio讲解 http协议 jdbc rmi java的安全框架等知识

    java 网络编程 代码集合

    在这个"java 网络编程 代码集合"中,包含了多个示例项目,覆盖了从基础的TCP/IP通信到高级的RMI(远程方法调用)以及SMTP(简单邮件传输协议)的应用。下面将对这些知识点进行详细解释。 1. **TCP/ECHO**:TCP...

Global site tag (gtag.js) - Google Analytics