JDK RMI框架及相关技术综述

1.RMI基本原理



 RMI框架为远程对象分别生成了客户端代理和服务端代理。(HelloWorld的实例中可以看到客户端端的远程对象为代理类。)位于客户端的代理类称为存根STUB,服务端的代理类称为骨架SKELETON。存根与骨架通过SOCKET进行通信。服务端与客户端之间传送的方法参数或返回值,必须是远程对象(Remote接口也集成Serializable接口)、可序列化对象、基本类型。

2.分布式垃圾回收

RMI框架采用分布式垃圾收集机制(DGC)来管理远程对象的生命周期,DGC的主要规则是,只有当一个远程对象不受到任何本地引用和远程引用,这个对象才会结束生命周期,并且可以被本地Java虚拟机的垃圾回收器回收。

服务器端如何知道客户端持有一个远程对象的远程引用呢?当客户端获得了一个服务器端的远程对象的存根时,就会向服务器发送一条租约通知,告诉服务器自己持有这个远程对象的引用了。客户端对这个远程对象有一个租约期限。租约期限可通过系统属性java.rmi.dgc.leaseValue来设置。默认为10分钟。当到达了租约期限的一半时间,客户端如果还持有远程引用,就会像服务器发送租约通知。如果在租约到期后,服务器端没有继续受到客户端的新的租约通知,服务器端就会认为这个客户已经不在持有远程对象的引用了。

RMI框架管理远程对象的生命周期的过程对应用程序是透明的。远程对象希望在不受到任何引用时执行一些操作,如释放占用的相关资源,以便安全地结束生命周期,这样的远程对象需要实现java.rmi.server.Unreferenced接口。

3.一个复杂点的应用

该程序模拟股票服务端往APP端推送股票实时价格。

package com.wilian.rmi.stock.server;

import java.rmi.Remote;
import java.rmi.RemoteException;

import com.wilian.rmi.stock.client.StockQuote;
/**
 * 服务端注册类,用户管理客户端的连接与释放
 * @author wilian
 *
 */
public interface StockQuoteRegistry extends Remote {
	void registerClient(StockQuote client) throws RemoteException;
	void unregisterClient(StockQuote client) throws RemoteException;
}

 

package com.wilian.rmi.stock.server;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;

import com.wilian.rmi.stock.client.StockQuote;
/**
 * 服务端实现类型
 * @author wilian
 *
 */
public class StockQuoteRegistryImpl extends UnicastRemoteObject implements
		Runnable,Unreferenced, StockQuoteRegistry {
	protected HashSet<StockQuote> clients;

	protected StockQuoteRegistryImpl() throws RemoteException {
		this.clients=new HashSet<StockQuote>();
	}

	@Override
	public void registerClient(StockQuote client) throws RemoteException {
		clients.add(client);
		System.out.println("加入一个客户端");
	}	

	@Override
	public void unregisterClient(StockQuote client) throws RemoteException {
		clients.remove(client);
		System.out.println("删除一个无效客户端");
	}

	/**
	 * 模拟进行股票价格的刷新
	 */
	@Override
	public void run() {
		String[] symbols=new String[]{"SUNW","DAL","MSFT","DAL","WUTK","SAMY","KATY"};
		Random rand=new Random();
		double[] values=new double[symbols.length];
		for(int i=0;i<values.length;i++){
			values[i]=25.0+rand.nextInt(100);
		}
		for(;;){
			int sym=rand.nextInt(symbols.length);
			
			int change=100-rand.nextInt(201);
			values[sym]=values[sym]+((double)change)/100.0;
			if(values[sym]<0) values[sym]=0.01;
			Iterator<StockQuote> iter = clients.iterator();
			while(iter.hasNext()){
				StockQuote client = iter.next();
				try {
					client.quote(symbols[sym], values[sym]);
				} catch (RemoteException e) {
					System.out.println("删除一个无效的客户端");
					iter.remove();
				}
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void unreferenced() {
		
	}

}

 

package com.wilian.rmi.stock.client;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
 * 股票打印远程实现对象
 * @author wilian
 *
 */
public class StockQuoteImpl extends UnicastRemoteObject implements StockQuote {

	protected StockQuoteImpl() throws RemoteException {}

	@Override
	public void quote(String stockSymbol, double price) throws RemoteException {
		System.out.println(stockSymbol+":"+price);
	}

}

 

package com.wilian.rmi.stock.client;

import java.rmi.Remote;
import java.rmi.RemoteException;
/**
 * 股票打印接口
 * @author Wilian
 *
 */
public interface StockQuote extends Remote {
	void quote(String stockSymbol,double price) throws RemoteException;
}

 

package com.wilian.rmi.stock.server;

import java.rmi.RemoteException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
 * 服务器端实现
 * @author wilian
 *
 */
public class Server {
	
	public static void main(String[] args) {
		try {
			StockQuoteRegistryImpl registry = new StockQuoteRegistryImpl();
			Context namingContext=new InitialContext();
			namingContext.rebind("rmi:StockQuoteRegistry", registry);
			//开启后台刷新线程
			new Thread(registry).start();
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (NamingException e) {
			e.printStackTrace();
		}
	}

}

 

package com.wilian.rmi.stock.client;

import java.rmi.RemoteException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.wilian.rmi.server.Flight;
import com.wilian.rmi.server.FlightFactory;
import com.wilian.rmi.stock.server.StockQuoteRegistry;

/**
 * 客户端
 * @author wilian
 *
 */
public class Client {

	public static void main(String[] args) {
		String url="rmi://localhost/";
		try {
			Context namingContext = new InitialContext();
			StockQuoteRegistry registry = (StockQuoteRegistry)namingContext.lookup(url+"StockQuoteRegistry");
		
			StockQuote client =new StockQuoteImpl();
			registry.registerClient(client);
			
		} catch (NamingException e) {
			e.printStackTrace();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

}

   运行截图:



 

 

从上面的例子可以看出,服务端也可以通过远程对象回调客户端。

 

参考资料:《Java网络编程精解》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值