Hadoop RPC 远程过程调用是Hadoop中的核心概念。在深入研究RPC之前,先看看远程调用的鼻祖Java RMI.
1.什么是RMI
Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。
Java RMI极大地依赖于接口。在需要创建一个远程对象的时候,程序员通过传递一个接口来隐藏底层的实现细节。客户端得到的远程对象句柄正好与本地的根代码连接,由后者负责透过网络通信。这样一来,程序员只需关心如何通过自己的接口句柄发送消息。
接口的两种常见实现方式是:
(1)最初使用JRMP(Java Remote Message Protocol,Java远程消息交换协议)实现;
(2)此外还可以用与CORBA兼容的方法实现。
RMI一般指的是编程接口,也有时候同时包括JRMP和API(应用程序编程接口),而RMI-IIOP则一般指RMI接口接管绝大部分的功能,以支持CORBA的实现。最初的RMI API设计为通用地支持不同形式的接口实现。后来,CORBA增加了传值(pass by value)功能,以实现RMI接口。然而RMI-IIOP和JRMP实现的接口并不完全一致。
2.RMI实例
RMI相关的类和接口都在jdk
java.rmi
包中。
RMI的基础是接口,RMI构架基于一个重要的原理:定义接口和定义接口的具体实现是分开的。
下面我们通过具体的例子,建立一个简单的远程计算服务和使用它的客户程序
一个正常工作的RMI系统由下面几个部分组成:
远程服务的接口定义
远程服务接口的具体实现
Stub 和 Skeleton 文件
一个运行远程服务的服务器
一个RMI命名服务,它允许客户端去发现这个远程服务
类文件的提供者(一个HTTP或者FTP服务器)
一个需要这个远程服务的客户端程序
下面我们一步一步建立一个简单的RMI系统。首先在你的机器里建立一个新的文件夹,以便放置我们创建的文件,为了简单起见,我们只使用一个文件夹存放客户端和服务端代码,并且在同一个目录下运行服务端和客户端。如果所有的RMI文件都已经设计好了,那么你需要下面的几个步骤去生成你的系统:
1、 编写并且编译接口的Java代码
2、 编写并且编译接口实现的Java代码
3、 从接口实现类中生成 Stub 和 Skeleton 类文件
4、 编写远程服务的主运行程序
5、 编写RMI的客户端程序
6、 安装并且运行RMI系统
2.1 接口
第一步就是建立和编译服务接口的Java代码。这个接口定义了所有的提供远程服务的功能,下面是源程序:
/**
*
*/
package com.renren;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* @author root
*
*/
public interface CalculatorRemoteInterface extends Remote {
//! 注意,这个接口继承自Remote,每一个定义的方法都必须抛出一个RemoteException异常对象
public abstract int add(int a, int b) throws RemoteException;
}
注意,这个接口继承自Remote,每一个定义的方法都必须抛出一个RemoteException异常对象
2.2 实现类
package com.renren;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
@SuppressWarnings("serial")
// 继承 UnicastRemoteObject 远程对象 这个一定要写 否则 服务器启动报异常
public class CalculatorRemoteObject extends UnicastRemoteObject implements
CalculatorRemoteInterface {
public CalculatorRemoteObject() throws RemoteException {
super();
// TODO Auto-generated constructor stub
}
/**
*
*/
private static final long serialVersionUID = 1L;
// @Override
public int add(int a, int b) {
// TODO Auto-generated method stub
return a + b;
}
}
2.3 打包
将上述两个java文件编译打包为rmi-test.jar
在编写server和client程序时需要依赖该jar包
2.4 Server
Server做的事很简单,代码注释很详细...
package com.test;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class Server {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
// 定义远程接口CalculatorRemoteInterface对象 用于绑定在服务器注册表上 该接口由CalculatorRemoteObject类实现
CalculatorRemoteInterface remoteObject = new CalculatorRemoteObject();
// 定义一个端口号
int port = 9999;
// 创建一个接受对特定端口调用的远程对象注册表 注册表上需要接口一个指定的端口号
LocateRegistry.createRegistry(port);
// 定义服务器远程地址URL格式
String serverAddress = "rmi://10.2.185.197:" + port+"/calculator" ;
// 绑定远程地址和接口对象
Naming.bind(serverAddress, remoteObject);
// 如果启动成功 则弹出如下信息
System.out.println(">>>服务器启动成功");
System.out.println(">>>请启动客户端进行连接访问");
} catch (MalformedURLException e) {
System.out.println("地址出现错误!");
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("重复绑定了同一个远程对象!");
e.printStackTrace();
} catch (RemoteException e) {
System.out.println("创建远程对象出现错误!");
e.printStackTrace();
}
}
}
2.5 Client
package com.test;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
CalculatorRemoteInterface calculator=
(CalculatorRemoteInterface) Naming.lookup("rmi://10.2.185.197:9999/calculator");
System.out.println("5+3="+calculator.add(5, 3));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NotBoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2.6 测试
1.在一台机器上启动Server
2.在两外一台机器上启动Client,可以看到Client成功调用了Server的CalculatorRemoteObject对象的add方法.
2.7 名词解释 Stub Skeleton
http://blog.sina.com.cn/s/blog_4ab0d57401009n4a.html
Stub(存根)和Skeleton(骨架)
参考:
http://blog.csdn.net/wangxingbao4227/article/details/6842951
http://blog.csdn.net/tin591/article/details/8117198
http://hi.baidu.com/dl_linfeng/item/330036304422c65c80f1a778