RMI
来源:互联网 发布:亲亲吉祥网络 编辑:程序博客网 时间:2024/06/06 15:53
RMI
一、RMI简介
RMI——Remote Method Invocation,即远程方法调用。是Java的一组拥护开发分布式应用程序的API。。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。
RMI主要用到了代理模式和序列化/反序列化。
二、RMI原理
一个RMI系统的组成元素:
1. 远程服务接口定义
2. 远程服务接口实现
3. 远程服务框架代理类(Skeleton)
4. 客户端桩代理类(Stub)
5. 客户端
6. 一个RMI命名服务或注册中心,允许服务端注册服务,客户端发现服务
基本原理:
RMI系统的运行过程:
1. 生成一个远程接口
2. 实现远程接口(服务端程序)
3. 注册远程服务到注册中心
4. 启动服务端,等待客户端调用
5. 编写客户端程序
6. 客户端去注册中心获取服务
7. 客户端调用
8. 服务端相应,处理服务,返回相应
9. 客户端拿到响应,一次交互结束。
时序图:
三、RMI实例
Server接口:
public interface MyRemote extends Remote {
public String sayHello() throws RemoteException;
}
ServerImpl:服务端实现类:
public class MyRemoteImpl implements MyRemote, Serializable {
public String sayHello() throws RemoteException {
return "server say Hello!";
}
public static void main(String args[]) {
MyRemote myRemote = new MyRemoteImpl();
try {
Registry registry = LocateRegistry.createRegistry(2001); //开一个端口
registry.rebind("RemoteHello", myRemote); //服务端注册
System.out.println("server is ready");
try {
Thread.sleep(1000 * 20); //由于是在一个工程内,同时runmain方法,这里sleep一下,保证客户端在20秒内调到
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
} catch (RemoteException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
Client:客户端类
public class Client {
public static void main(String args[]) {
try {
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 2001);
MyRemote myRemote = (MyRemote) registry.lookup("RemoteHello"); //从注册中心取到服务
String s = myRemote.sayHello();//客户端请求服务
System.out.println("s=" + s);
} catch (NotBoundException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (RemoteException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
四、RMI原理模拟
Server:
package com.mylearn.rmi.principle.remote;
/**
* Created by IntelliJ IDEA.
* User: yingkuohao
* Date: 13-10-30
* Time: 下午5:21
* CopyRight:360buy
* Descrption: 声明接口,客户端和服务端都要知道
* To change this template use File | Settings | File Templates.
*/
public interface Server {
/**
* 提供服务一: sayHello
*
* @return
*/
public String sayHello();
/**
* 提供服务二: sayLove
*
* @return
*/
public String sayLove();
}
ServerImpl:
package com.mylearn.rmi.principle.remote;
import java.io.Serializable;
/**
* Created by IntelliJ IDEA.
* User: yingkuohao
* Date: 13-10-30
* Time: 下午5:24
* CopyRight:360buy
* Descrption: 服务端具体实现类,注意要实现Serilizable接口
* To change this template use File | Settings | File Templates.
*/
public class ServerImpl implements Server, Serializable {
public String sayHello() {
return "server say hello!"; //To change body of implemented methods use File | Settings | File Templates.
}
public String sayLove() {
return "server say love!"; //To change body of implemented methods use File | Settings | File Templates.
}
}
Server_Skeleton :服务端代理类
package com.mylearn.rmi.principle.remote;
import javax.print.attribute.standard.Severity;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by IntelliJ IDEA.
* User: yingkuohao
* Date: 13-10-30
* Time: 下午5:23
* CopyRight:360buy
* Descrption: 服务端代理类,代理类的作用就是实现类的封闭,
* 1. 这里接收客户端的字节流,然后解析出客户端要请求的服务,
* 2.然后找到服务的本尊,调用对应的方法,得出结果
* 3. 然后把结果序列化,通过流的方式返回给客户端(其实也是客户端的代理对象)
* To change this template use File | Settings | File Templates.
*/
public class Server_Skeleton implements Runnable {
private Server server; //声明代理对象
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(9090); //开启socket服务端
while (true) {
Socket socket = serverSocket.accept(); //等待客户端请求
System.out.println("服务端建立socket链接ok!");
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
String method = (String) objectInputStream.readObject(); //获取客户端请求方法,反序列化
if ("sayHello".equalsIgnoreCase(method)) {
//如果是saylHello方法,则调用ServerImpl去处理,代理模式
server = new ServerImpl();
String s = server.sayHello();
objectOutputStream.writeObject(s); //序列化
objectOutputStream.flush();
}
if ("sayLove".equalsIgnoreCase(method)) {
//如果是sayLove方法,则调用ServerImpl去处理
server = new ServerImpl();
String s = server.sayLove();
objectOutputStream.writeObject(s);
objectOutputStream.flush();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
outputStream.close();
inputStream.close(); //输入流不能提前关闭,否则报错
socket.close();
System.out.println("服务端响应结束");
}
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (ClassNotFoundException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
Client_Stub:客户端代理类
package com.mylearn.rmi.principle.local;
import com.mylearn.rmi.principle.remote.Server;
import java.io.*;
import java.net.Socket;
/**
* Created by IntelliJ IDEA.
* User: yingkuohao
* Date: 13-10-30
* Time: 下午5:24
* CopyRight:360buy
* Descrption: 客户端代理类
* 1. 把客户端的请求通过流传给服务端(其实是服务端的代理类)
* 2. 阻塞,等待服务端的返回,如果有响应,则读取响应信息,反序列化,展现结果
* To change this template use File | Settings | File Templates.
*/
public class Client_Stub implements Server {
private Socket socket;
private void connect() {
try {
socket = new Socket("127.0.0.1", 9090);
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
public String sayHello() {
return say("sayHello");
}
public String sayLove() {
return say("sayLove");
}
public String say(String fieldName) {
connect();//建立到服务端的链接
try {
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(fieldName); //向服务端发送请求,序列化,请求调用服务端的sayHello方法
// System.out.println("客户端发送请求,request sayHello接口");
objectOutputStream.flush();
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
return (String) objectInputStream.readObject(); //阻塞,等待服务端发送消息,反序列化
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (ClassNotFoundException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
return null;
}
}
Client:
package com.mylearn.rmi.principle.local;
import com.mylearn.rmi.principle.remote.Server_Skeleton;
/**
* Created by IntelliJ IDEA.
* User: yingkuohao
* Date: 13-10-30
* Time: 下午5:21
* CopyRight:360buy
* Descrption: 客户端对象
* To change this template use File | Settings | File Templates.
*/
public class Client {
public static void main(String args[]) {
//1.开一个服务器线程
final Thread threadServer1 = new Thread(new Server_Skeleton());
//2.开5个客户端线程请求sayHello
for (int i = 0; i < 5; i++) {
Thread threadClient1 = new Thread(new Runnable() {
public void run() {
Client_Stub client_stub = new Client_Stub();
String response = client_stub.sayHello();
System.out.println("response1 = " + response);
}
});
threadClient1.start();
}
//3.开5个客户端线程请求sayLove
for (int i = 0; i < 5; i++) {
Thread threadClient2 = new Thread(new Runnable() {
public void run() {
Client_Stub client_stub = new Client_Stub();
String response = client_stub.sayLove();
System.out.println("response2 = " + response);
}
});
threadClient2.start();
}
threadServer1.start();//启动服务端代理类线程
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
五、设计模式延伸
代理模式: 代理模式控制对象的访问。在代理类中会对客户端的访问做限制,达到某个条件才会调用对象本尊。如上文中的Server_Skeleton和Client_Stub对象都是代理类。ServerImpl是服务本尊。
装饰模式:装饰模式为对象增加行为。
适配器模式:代理和适配器都是会挡在其他对象的前面,并负责将请求转发给它们。适配器会改变对象适配的接口,而代理则实现相同的接口。
推荐: http://haolloyin.blog.51cto.com/1177454/332426
- RMI
- rmi
- RMI
- RMI
- RMI
- RMI
- rmi
- RMI
- RMI
- RMI
- RMI
- RMI
- rmi
- RMI
- RMI
- RMI
- RMI
- RMI
- ECHO命令的使用
- 南阳理工OJ_鸡兔同笼
- Hibernate Mapping笔记
- nginx中如何限制某个IP同一时间段的访问次数
- BootStrap入门教程 (三)
- RMI
- 使用CInternetSession和CHttpFile读取网页内容
- bat 批处理 字符串 替换函数 和 字符串截取函数
- 求一个角度的sin,cos值的demo
- BAT 批处理文件与环境变量
- ubuntu下搭建nagios
- basic view
- Documentation/sound/alsa/powersave.txt
- BAT 延迟变量