Java RMI指的是远程方法调用(Remote Method Invocation)。它是一种机制,能够让在某个机器上的Java程序调用另一个机器上的Java程序的方法,用此方法调用的任何对象必须实现该远程接口。EJB就是建立在RMI基础之上的。

本节将讲解RMI的基本概念和系统原理,通过一些入门实例讲解RMI程序的开发步骤和编译运行方法。

RMI是RPC(远程过程调用)的Java版本的实现,远程过程调用是一种计算机分布式通信协议,包括Client/Server模型和分布式对象模型。

RPC(Remote Procedure Call)是计算机分布式通信协议。该协议允许运行与一台计算机的程序调用另一台计算机的子程序,而程序员无须为这个交互进行编程。

RPC总是由客户端对服务端发出一个执行若干过程的请求,并且利用客户端提供的参数,执行结果返回客户端。

为了允许不同的客户端均能访问服务端,许多RPC采用了接口描述语言IDL,方便跨平台的远程过程调用。

客户机/服务器模型Client/Server是分布式通信的一种形式。在这种新式中,客户机和服务器通信一遍交换信息。客户机/服务器的典型做法是使用底层套接字。Socket和NIO Socket编程就是套接字编程的两种Java实现

分布式对象模型

基于分布式对象的系统是一组对象的组合,这些对象以一种明确定义封装的接口把服务的请求着和服务的提供者分隔开。Java远程方法调用RMI和共用对象请求代理体系(CORBA)就是这种模型的例子。RMI仅适用于Java语言,CORBA支持多语言比较复杂。

Java远程方法调用RMI是Java编程语言里一种用于实现远程过程调用的应用程序编程接口,它使客户机上运行的程序可以调用远程服务器上的对象。RMI极大地依赖于接口。

RMI系统原理与开发步骤

RMI通信机制:RMI通常包括两个独立的程序:服务器和客户机程序

在与远程对象的通信过程中,RMI使用标准机制:Stub(存根)和Skeleton(框架)

在RMI分布式应用系统中,服务器和客户机之间的传递的Java对象必须是可序列化的对象,不可序列化的对象不能在对象流中进行传递。

RMI程序的实现步骤

将远程类的功能定义为Java接口。在Java中远程对象是实现远程接口的类的实例。

  • 远程接口必须声明为public。

  • 远程对象扩展java.rmi.Remote接口

  • 每个方法必须抛出java.rim.RemoteException

  • 任何作为参数或者返回值传送的远程对象的数据类型必须声明为远程接口类型。

RMI程序开发详解

  • 创建一个远程接口类

  • 创建一个接口实现类

  • 开发服务器端程序,启动远程接口服务

  • 开发客户端,访问远程接口服务

编译和运行的步骤如下:

  • 编译生成Stub和Skeleton

  • 启动RMI注册表

  • 启动服务器

  • 运行客户端

我们将通过一个开发一个HelloWorld入门程序来实践这些步骤。

实现类包括:

远程借口类ITestRemote

实现类TestRemote

服务器RMIServer

客户端RMIClient

调用关系

创建远程接口类ITestRemote.java

package org.test.rmi;import java.rmi.Remote;
import java.rmi.RemoteException;/*** @author kucs* 定义远程接口,提供了dealData的方法* 扩展了Remote* 远程接口类必须声明为public* 必须继承自java.rmi.Remote* 必须抛出一个java.rmi.RemoteExcetion例外*/
public interface ITestRemote extends Remote {public String dealData(String world) throws RemoteException;}

远程借口实现类TestRemote.java

package org.test.rmi;import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;/*** @author kucs** 远程接口ITestRemote的实现类* 扩展了UnicastRemoteObject,* 表示TestRemote类将用于创建一个单独的、不可复制的远程对象* 它使用RMI默认的TCP的传送通道进行通信*/
public class TestRemote extends UnicastRemoteObject implements ITestRemote {/*** */private static final long serialVersionUID = 1L;protected TestRemote() throws RemoteException {super();}@Overridepublic String dealData(String world) throws RemoteException {// TODO Auto-generated method stubreturn "你好,"+world;}}

服务器RMIServer.java

package org.test.rmi;import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;/*** @author kucs* 服务器需要做的3件事* 1、创建RMI安全管理器RMISecurityManager的一个实例并安装它* 2、创建远程对象的一个实例,在本实例中是TestRemote* 3、在RMI注册表中登记这个创建的对象*/
public class RMIServer {public static void main(String[] args) {// TODO 创建并安装安全管理器if(System.getSecurityManager() == null){System.setSecurityManager(new RMISecurityManager());}try {// TODO 创建远程对象ITestRemote test = new TestRemote();// TODO 启动注册表LocateRegistry.createRegistry(1099);//将名称绑定到对象Naming.rebind("//localhost:1099/TestRemoteService", test);System.out.println("RMI服务器正在运行....");} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

客户端RMIClient.java

package org.test.rmi;import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;/*** @author kucs* 客户端可以远程调用远程接口中指定的任何方法。* 客户端必须从RMI注册表中获得指向该远程对象的引用* 客户端需要做3件事* 1、创建RMI安全管理器RMISecurityManager的一个实例并安装它* 2、根据IP、端口号、服务名查找远程主机的服务并取得该服务的实例* 调用该实例的本机接口方法* */
public class RMIClient {public static void main(String[] args) {// TODO 创建并安装安全管理器if(System.getSecurityManager() == null){System.setSecurityManager(new RMISecurityManager());;}try {ITestRemote test = (ITestRemote) Naming.lookup("rmi://localhost:1099/TestRemoteService");System.out.println(test.dealData("我是客户端"));System.out.println(test.dealData("中国"));} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NotBoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

编译并运行应用程序

为了运行应用程序,我们需要生成Stub和Skeleton,编译服务器和客户端程序,启动RMI注册表,最后是启动服务器和运行客户端程序

(1)编译生成Stub和Skeleton

为了生成Stub和Skeleton,我们使用rmi编译器编译实现类TestRemote.class。在项目功能目录的bin目录下,启动cmd。执行如下命令及结果如图示。这将生成TestRemote_Stub.class。TestRemote_Stub.class是一个客户机代理,TestRemote_Skel.class是一个服务器基干。        (2)启动RMI注册表,因为D我们在代码中添加了LocateRegitry.createRegistry(1099)语句,所以在启动服务器时自动自动RMI注册表

(3)编写安全许可文件

因为在服务器应用程序中正在使用RMI安全管理员,所以需要一个安全许可文件来与之匹配。安全许可文件policy.txt,我们将它保存在无包的目录下。

grant{permission java.security.AllPermission "*:1000-9999","accept,connect,listen,resolve";
};

(4)启动服务器命令java -Djava.security.policy=policy.txt org.test.rmi.RMIServer

(5)运行客户机命令java -Djava.security.policy=policy.txt org.test.rmi.RMIClient

运行结果

安全管理器

当没有写策略文件覆盖C:\Program Files\Java\jre1.6.0_05\lib\security里的java.policy时,调用

if(System.getSecurityManager()==null)

System.setSecurityManager(new RMISecurityManager());

系统会抛出异常 java.security.AccessControlException。
原因:每个Java应用都可以有自己的安全管理器,它是防范恶意***的主要安全卫士。安全管理器通过执行运行阶段检查和访问授权,以实施应用所需的安全策略,从而保护资源免受恶意操作的***。实际上,安全管理器根据Java安全策略文件决定将哪组权限授予类。然而,当不可信的类和第三方应用使用JVM 时,Java安全管理器将使用与JVM相关的安全策略来识别恶意操作。在很多情况下,威胁模型不包含运行于JVM中的恶意代码,此时Java安全管理器便不是必需的。当安全管理器检测到违反安全策略的操作时,JVM将引发 AccessControlException或SecurityException。
  在Java应用中,安全管理器是由System类中的方法setSecurityManager设置的。要获得当前的安全管理器,可以使用方法 getSecurityManager。 java.lang.SecurityManager类包含了很多checkXXXX方法,如用于判断对文件访问权限的checkRead(String file)方法。这些检查方法调用SecurityManager.checkPermission方法,后者根据安全策略文件判断调用应用是否有执行所请求的操作权限。如果没有,将引发SecurityException。  如果想让应用使用安全管理器和安全策略,可在启动JVM时设定-Djava.security.manager选项,还可以同时指定安全策略文件。如果在应用中启用了Java安全管理器,却没有指定安全策略文件,那么Java安全管理器将使用默认的安全策略,它们是由位于目录$JAVA_HOME/jre /lib/security中的java.policy定义的。 类装载器用Policy对象帮助它们决定,把一段代码导入虚拟机时应该给它们什么样的权限. 任何时候,每一个应用程序都只有一个Policy对象.
2.有关rmic的疑惑rmic是为客户端和服务器端生成相关的存根和骨架(实际上就是一种代理类),但是我们直接在javac java的过程就可以直接调用远程方法,好像没有rmic的调用。
原因:在jdk5.0以前的版本中,需要用rmic命令来为远程对象生成静态的代理类(包括存根和骨架类),而在jdk5.0中rmi框架会在运行的过程中自动为远程 对象生成动态代理类(包括存根和骨架类),从而更彻底的封装了rmi框架的实现细节。简化了rmi框架的使用方式。
3.registry本地注册表
实际上LocateRegistry.createRegistry(rmiPort)就是创建对远程或者本地注册表的本地引用,创建并导出Registry实例。

RMI实现了客户端与远程主机的调用,但是客户端和服务器必须都是基于Java语言的。如果要实现非Java语言之间的调用,就必须使用CORBA了。

转载于:https://blog.51cto.com/aku28907/1783003

Java网络编程基础(七)— RMI分布式网络编程相关推荐

  1. java 网络爬虫 正则表达式_【干货】Java网络爬虫基础知识

    原标题:[干货]Java网络爬虫基础知识 引言 Java 网络爬虫具有很好的扩展性可伸缩性,其是目前搜索引擎开发的重要组成部分.例如,著名的网络爬虫工具 Nutch 便是采用 Java 开发,该工具以 ...

  2. Java网络爬虫基础概述

    Java网络爬虫基础 Http基础 网络资源一般是Web服务器上的一些各种格式的文件,通过Http协议传输互联网上的数据. 在Java中,通常通过URL标出网络资源的位置和Web服务器建立链接,获取网 ...

  3. 编程基础 垃圾回收_编程中的垃圾回收指南

    编程基础 垃圾回收 什么是垃圾回收? (What is Garbage Collection?) In general layman's terms, Garbage collection (GC) ...

  4. 南开大学python编程基础_《Python编程基础》20春期末考核(参考答案)南开大学 答案...

    <Python编程基础>20春期末考核 -00001 试卷总分:100  得分:70 一.单选题 (共 15 道试题,共 30 分) 1.执行"print(0o20)" ...

  5. WebFlux响应式编程基础之 2 函数式编程 工具jclasslib bytecode viewer

    函数式编程:告诉他的功能是什么,而不是告诉他怎么做 命令式编程:怎么去做 函数式编程:不需要关注细节,利用系统已经有的API 使用jdk8自带函数接口的好处 函数接口减少接口定义 函数式接口链式操作 ...

  6. Python编程基础21:GUI编程

    文章目录 零.本讲学习目标 一.图形用户界面 - GUI (一)GUI概述 (二)常用的Python GUI库 1.Tkinter库 2.wxPython库 3.Jython库 二.tkinter编程 ...

  7. c语言编程基础心得,C语言编程学习心得体会

    C语言是在国内外广泛使用的一种计算机语言.其语言功能丰富.表达能力强.使用灵活方便.既具有高级语言的优点,又具有低级语言的许多特点,适合编写系统软件.本文是C语言编程学习心得,希望对大家有帮助. C语 ...

  8. c语言编程基础 教案,C语言编程基础电子教案.doc

    C语言编程基础电子教案 课题(内容)1.1 C语言简史及特点课时1教学任务分析教学目标知识技能通过本节课的教学,使学生了解并熟悉编程语言C的发展历史.特点及其种类和适用范围.过程与方法通过C语言的发展 ...

  9. spark编程基础python版 pdf_Spark编程基础Python版-第5章-Spark-SQL.pdf

    <Spark编程基础(Python版)> 教材官网:/post/spark-python/ 温馨提示:编辑幻灯片母版,可以修改每页PPT的厦大校徽和底部文字 第5章Spark SQL (P ...

最新文章

  1. c将字符串拆分,并存入结构体
  2. 20210614 So-called的用法
  3. xhtml的行内描述性元素
  4. python文件读取模式_day-2 python 文件读写模式r,r+,w,w+,a,a+的区别
  5. linux内核启动失败,裁剪后montavistalinux内核 nfs启动失败
  6. 第二轮冲刺-Runner站立会议08
  7. 【OpenCV 例程200篇】03. 图像的显示(cv2.imshow)
  8. 1601 - The Morning after Halloween
  9. 【C#/WPF】Image图片的Transform变换:平移、缩放、旋转
  10. Keras下使用多GPU训练模型
  11. CI框架(4)-页面跳转
  12. JavaWeb新闻发布系统案例4
  13. h桥控制电机刹车_基于H桥控制直流电机驱动电路设计
  14. Couldn‘t find executable named person_subscriber below /home/yue/catkin_ws/src/... 找不到可执行文件的原因
  15. 还不知道什么是cms 什么是 cmf?
  16. 天地波超视距雷达在远洋无人航运中的运用
  17. 程序员约架事件中,薛非为何不应战?
  18. 电脑托文件到服务器,本地电脑文件拖入云服务器
  19. 各种电平标准的讨论(TTL,ECL,PECL,LVDS、CMOS、CML.......)
  20. java基础小记_Java基础学习小记--多态

热门文章

  1. java a运算顺序_Java中计算顺序的规则是什么?
  2. wpf窗口向左向上_PaperWM:GNOME 下的平铺窗口管理
  3. 适合win7的python版本_windows下多个python版本共存,如何在Windows7系统上安装最新的64位Python3.6.2...
  4. 学生管理系统(C语言版)
  5. 试题 入门训练 Fibonacci数列(Java)
  6. hdc mfc 画扇形图_使用echarts绘制条形图和扇形图
  7. 数据结构学习系列文章合集
  8. 错误: 编码 GBK 的不可映射字符 (0x80)
  9. Android架构篇-3 网络接口封装
  10. ios NSLayoutConstraint