文章的标题看起来很诡异,较深入?谷歌搜索Java RMI会看到好多作者写关于RMI的东西,基本上是介绍RMI的基础知识和HelloWorld RMI版的,当然也可以看到用Java RMI来开发聊天工具的。
RMI HelloWorld 那么就只有服务器和客户端,客户端只请求服务器的一些服务,服务器不会请求客户端的方法;聊天工具,那么服务器也是客户端,客户端也是服务器,因为二者存在数据的交互。
由于聊天工具写起来麻烦,所以就写了个加减乘除运算的服务器和客户端交互的代码,主要介绍客户端怎么如同服务器一样把自己的接口方法广播出去(用‘广播’应该不合适,意思就是让服务器通过网络连接来调用客户端接口方法)和服务器是怎么样调用客户端的方法的。
看懂下面的代码需要有简单的RMI基础,最起码要知道HelloWorld是怎么实现的。
首先给出Multi的接口:
package RMITest.MultiandPlus;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Multi extends Remote{
public int mul(int a,int b) throws RemoteException;
}
再给出实现Multi接口的方法MultiImpl
package RMITest.MultiandPlus;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class MultiImpl extends UnicastRemoteObject implements Multi {
private String name;
public MultiImpl(String str) throws RemoteException{
super();
this.name = str;
}
public MultiImpl() throws RemoteException{
super();
}
public int mul(int a,int b) throws RemoteException{
return a * b;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
接着给出Plus接口:
package RMITest.MultiandPlus;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Plus extends Remote{
public int plus(Sub s,int a,int b,int c) throws RemoteException;
}
同样给出PlusImpl:
package RMITest.MultiandPlus;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class PlusImpl extends UnicastRemoteObject implements Plus {
private String name;
public PlusImpl(String str) throws RemoteException{
super();
this.name = str;
}
public PlusImpl() throws RemoteException{
super();
}
public int plus(Sub s,int a,int b,int c) throws RemoteException{
int d = a+b;
return s.sub(d,c);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
Multi和Plus都需要在服务器端来进行运算,下面给出服务器端的代码:
package RMITest.MultiandPlus;
import java.rmi.RMISecurityManager;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class CMSServer implements Multi,Plus{
public static void main(String[] args) {
// TODO Auto-generated method stub
//System.setSecurityManager(new RMISecurityManager());
try{
// Multi obj1 = new MultiImpl();
//
// Plus obj2 = new PlusImpl();
//
MultiImpl obj1 = new MultiImpl("MultiServer");
PlusImpl obj2 = new PlusImpl("PlusServer");
LocateRegistry.createRegistry(2099);
LocateRegistry.createRegistry(3099);
Naming.bind("rmi://localhost:2099/MultiServer", obj1);
Naming.bind("rmi://localhost:2099/PlusServer", obj2);
//Naming.bind("multi", obj1);
//Naming.bind("plus", obj2);
}catch(Exception e){
e.printStackTrace();
}
}
@Override
public int plus(Sub s,int a, int b,int c) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int mul(int a, int b) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
}
大家应该能看到在Plus接口的plus方法中有个‘Sub’,这个就是Sub接口,该接口中的sub方法要在客户端实现
给出Sub接口:
package RMITest.MultiandPlus;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Sub extends Remote{
public int sub(int a,int b) throws RemoteException;
}
由于我们需要在客户端实现sub方法,那么这里就直接省去原本应该有的SubImpl类,直接全部放到客户端的代码中
客户端代码:
package RMITest.MultiandPlus;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Scanner;
public class CMSClient implements Sub{
public CMSClient(){
super();
try{
UnicastRemoteObject.exportObject(this,0);//这里是核心,该句就是将自己的Sub中的sub方法广播出去使服务器能够调用sub方法
}catch(Exception e){
System.out.println("Exception "+e);
}
}
public void init(){
try {
Plus p = (Plus) Naming.lookup("rmi://localhost:2099/PlusServer");
Multi m = (Multi) Naming.lookup("rmi://localhost:2099/MultiServer");
// Plus p = (Plus)Naming.lookup("plus");
// Multi m = (Multi)Naming.lookup("multi");
Scanner in = new Scanner(System.in);
while(in.hasNext()){
int a = in.nextInt();
int b = in.nextInt();
int c = in.nextInt();
int d = in.nextInt();
System.out.println(m.mul(p.plus(this,a, b,c), d));
}
} 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();
}
}
public int sub(int a,int b){//具体实现sub方法
return a - b;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
CMSClient c = new CMSClient();
c.init();
}
}
该客户端首先输入a,b,c,d四个整数,然后先计算a+b的值接着用a+b-c得到结果乘以d就是最终答案。
本文的例子是在Java网络高级编程一书中看到的,只是将里面的(a+b)*c的例子稍加修改,这样就基本上能够很清晰的讲解如何实现Java RMI聊天工具的。
其核心就是客户端和服务器的交互,这样其实也就没有了客户端和服务器之分。
简单说一下:
如果把CMSClient类中的UnicastRemoteObject.exportObject(this,0)改成UnicastRemoteObject.exportObject(this);该程序是运行不起来的,直接报错,具体的错误原因我真心不知道,如果有高手路过还劳烦给我讲解一些。
有了上面的技术支持那么就可以简单开发一个网络对战版的五子棋游戏并且游戏中支持聊天功能,想法是不是不错,其中应该还需要用到线程的知识。
最后如果代码有看不懂的欢迎与我交流。