`
s929498110
  • 浏览: 105241 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

RMI 菜鸟游记【纸上谈兵】

阅读更多

最近想学习一下Web底层机制,也不知道从哪里开始看起。 找了一本差不多的书《Java网络高级编程》,看到RMI这一块,发现自己看不明白,就网络上各处寻找资料,鼓捣了一晚上,终于明白了怎么回事。发出来显摆OR丢人一下

大神们手下留情啊。 上次被弄了一个新手帖,悲剧死了。。。

 

Java Remote Method Invocation ( RMI -- Java远程方法调用 ) 允许您使用 Java 编写分布式对象  

RMI(远程方法调用)的组成

一个正常工作的RMI 系统由下面几个部分组成:

1、 远程服务的接口定义

2、 远程服务接口的具体实现

3、 桩(Stub )和框架( Skeleton )文件

4、 一个运行远程服务的服务器

5、 一个RMI 命名服务,它允许客户端去发现这个远程服务

6、 类文件的提供者(一个HTTP 或者 FTP 服务器)

7、 一个需要这个远程服务的客户端程序

RMI(远程方法调用)的工作原理

        RMI系统结构,在客户端和服务器端都有几层结构。 方法调用从客户对象经占位程序(Stub) 、远程引用层 (Remote Reference Layer) 和传输层( Transport Layer )向下,传递给主机,然后再次经传 输层,向上穿过远程调用层和骨干网( Skeleton ),到达服务器对象。 占位程序扮演着远程服务器对象的代理的角色,使该对象可被客户激活。 远程引用层处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。传输层管理实际的连接,并且追追踪可以接受方法调用的远程对象。服务器端的骨干网完成对服务器对象实际的方法调用,并获取返回值。返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,占位程序获得返回值。

要完成以上步骤需要有以下几个步骤:

1、  生成一个远程接口

2、  实现远程对象( 服务器端程序 )

3、  编写服务器程序 、注册远程对象、启动远程对象

4、  编写客户程序

 

RMI的实现原理

 

1、  调用者(Client )以通常方法 obj.invoke() 调用一个本地接口的远程实现类的实例

2、  顾客Stub 的功能把有关的远程调用参数封装为一个消息包(数据包)或者一组消息包,第一步调用访问的远程服务的地址( rmi://localhost:1099/ )、对象( obj )、调用方法( invoke() )及其参数都包含在这条消息中

3、  调用者(Client )本地 RMI Runtime 将这条消息发送给对应的服务器地址( rmi://localhost:1099/ RMI Runtime rmi 协议基于 tcp/ip 协议),服务器端 RMI Runtime 寻找绑定远程对象的进程(某个 javaw.exe ),然后调用这个进程中绑定的远程对象的指定方法,执行之后,将执行结果返回给调用者( Client )(其中的运行涉及到序列化和反序列化,因此为了平台兼容性每个有关 java 类都最好实现序列化。经常看到有人压制序列号警告而不是添加一个序列化 ID 。。。)

4、  调用者(Client RMI Runtime 接受到返回的结果,然后将此结果反序列化并且返回到调用方法。

   

       在以上回避了一个重要问题,即Client 怎么知道并调用 Server 上某个远程对象呢?这里就用到了命名服务。命名服务( Name Service )是分布式系统基本的公共服务。 Java 远程方法调用利用 RMI 机制提供命名服务。命名是给一个对象起一个名字,也就是就是说把名字绑定( binding )到该对象上,也就是以 Key|Value mapping 存储在 RMI 上的,它的目的就是用人们容易理解的名字代替计算机中人们不易理解的存储表示对象。 Client 通过 Server 上的某个 key(String 类型 ) 获取指定的 value(Object 类型 ) ,这个 value 是一种实现类,这个实现类所实现的规范或者说是接口本地一定要有,然后本地调用的就是这个接口的远程实现了。由此可见, RMI 的命名服务在 RMI 服务器端为 RMI 服务器提供者提供发布 RMI 服务对象的功能,在 RMI 客户端为 RMI 客户提供搜索远程 RMI 服务对象的功能

 

实例

1、远程接口
该接口定义了一个方法,用于提供远程服务

package net.sulin.test.rmi;

import java.rmi.Remote;

import java.rmi.RemoteException;

public interface Upper  extends Remote {

public String UpperString(String param)

            throws RemoteException ;

}
 

 

 

2、 实现远程对象( 服务器端程序 )

用来创建一个 Upper对象,然后由远程客户端获取

package net.sulin.test.rmi;

import java.rmi.RemoteException;

import java.rmi.server.UnicastRemoteObject;

public class UpperImpl extends UnicastRemoteObject 

                      implements Upper  {

private static final long 

               serialVersionUID = 806571139035814115L;

protected UpperImpl() throws RemoteException {

super();

}

@Override

public String UpperString(String param) 

                  throws RemoteException {

System.out.println("remote invoking successfully");

return param.toUpperCase();

}

}
 

3 、编写服务器程序 、注册远程对象、启动远程对象
代码:远程对象的注册类 该类应该在服务器端执行 执行之后, 该机器将变为RMI 服务器 客户端可以通过正确的 url 来访问;服务器上的远程对象;执行对外报露的方法

package net.sulin.test.rmi;

import java.rmi.Naming;

public class ServerBad {

public static void main(String[] args) throws Exception {

UpperImpl upp = new UpperImpl();

Naming.rebind("upper", upp);

System.out.println("Bind successfully");

}

}
 

 

运行该服务端代码后,将会注册一个远程服务对象

4 、编写客户程序
代码首先获取一个远程对象,然后如同本地调用一样,调用远程对象中的方法。

package net.sulin.test.rmi;

import java.rmi.Naming;

public class Client {

public static void main(String[] args) throws Exception {

Upper upper = (Upper) Naming.lookup("upper");

System.out.println(upper.UpperString("aaaaaa"));

}

}
 

 

 

这些之后,还不行的。  还需要做下列的一系列事情:

1、 使用 rmic 编译一个能被 RMI 服务使用的 clsss 文件

这个clsss 就是需要远程调用的类。在这里就是 UpperImpl.class

记住,先javac UpperImpl.java 、 再 rmic UpperImpl

2、 然后就是启动 rmi 服务了。 打开控制台,输入 start rmiregistry ,再按回车就 OK

最后一步就是启动服务类 ServerBad

这里是最容易出错的,参见下面注意事项。
注意:   如果提示找不到Stub 类,这个需要用下面的命令来运行
java.exe  -Djava.rmi.server.codebase =file:/ *_stub.class /   ServerBad

*_stub.clss就是第一步生成的 *_stub.class 的文件绝对路径

3、 启动你的客户端程序吧

你难道就不好奇我的服务类为什么是 Server Bad 因为我感觉这种方法太麻烦了。。。

还有一种更简单的方法,使用 java.rmi.registry .Registry动态注册一个绑定指定端口(可选,默认 1099 )的 rmi 服务。

服务端的类可以换为

package net.sulin.test.rmi;

import java.rmi.registry.LocateRegistry;

import java.rmi.registry.Registry;

public class Server {

public static void main(String[] args) throws Exception {

bind();

}

public static Registry createRegistry() throws Exception {

Registry registry = null;

final int port = 2222;

registry = LocateRegistry.createRegistry(port);

return registry;

}

public static void bind() throws Exception{

Registry registry = null;

registry = createRegistry();

Upper upp = new UpperImpl();

registry.bind("upper", upp);

System.out.println("My RMI Bind Successfully");

}

}
 

 

 

 

以上部分是单一的 Client-Server  的远程方法调用

还有一对多的Client(one)-Server(many) 的远程方法调用,即服务器端有多个,不但可以分散请求压力,还可以防止服务器出现故障导致的一系列问题

还有一种Client/Server 的远程方法调用,即一个网络点即可以是 Client 也可以是 Server

还有服务器链的远程方法调用,即Client-Server-Server...... 。  Client 请求的第一个 Server 不能完成全部工作,就可以设置服务器链,利用多个 Server 同步响应一个调用请求

后面这几种都是基于上面的单一远程方法调用。很容易理解的

 

 

下来看到第三章CORBA 、 本来是看网络通信底层的,怎么书上讲到分布式开发上了。。。

分享到:
评论
3 楼 s929498110 2011-04-18  
liubey 写道
问LZ一下 那本书写的怎么样啊


差不多吧。 但是也不算好

  国产书, 你懂的!!! 互相抄袭的

但是看着收获还是不小的, 书里面有很简单、很基础的东西。 也有企业级的分布式的东西
2 楼 Technoboy 2011-04-18  
http://technoboy.iteye.com/blog/983155
1 楼 liubey 2011-04-18  
问LZ一下 那本书写的怎么样啊

相关推荐

Global site tag (gtag.js) - Google Analytics