« | August 2025 | » | 日 | 一 | 二 | 三 | 四 | 五 | 六 | | | | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | | | | | | | |
| 公告 |
戒除浮躁,读好书,交益友 |
Blog信息 |
blog名称:邢红瑞的blog 日志总数:523 评论数量:1142 留言数量:0 访问次数:9690920 建立时间:2004年12月20日 |

| |
[java语言]RMI 编程 经常遇到的问题 原创空间, 软件技术, 电脑与网络
邢红瑞 发表于 2006/7/18 19:45:12 |
很久不写RMI程序了,一直使用spring的exporter,人变得懒了。写了一个以后备忘, 创建RMI远程对象后,程序员就可以象调用本地对象那样去调用远程对象,其底层通信机制则完全由RMI实现,无须我们操心了。通常,实现一个RMI系统有4个步骤:1:定义一个remote interface.2: 定义一个remote object implementation.3: 定义客户端程序。4:编译执行远程对象和客户端。
以下为代码示例 服务器端1:Remote接口 (注意:必须extends Remote,方法必须throws RemoteException)
接口import java.rmi.*;
public interface RmiHelloRemoteIntfc extends Remote{ public Basic getBasic(Long a) throws RemoteException;}2 remote object implementation.(注意:1:extends UnicastRemoteObject,也可以使用exportObject 2:构造函数内必须调用UnicastRemoteObject的构造函数,也就是执行super())import java.rmi.server.*;import java.rmi.*;import java.util.Random;import java.util.List;import java.util.ArrayList;
public class RmiHelloRemoteObj extends UnicastRemoteObject implements RmiHelloRemoteIntfc{
public RmiHelloRemoteObj() throws RemoteException { super(); }
public Basic getBasic(Long a) throws RemoteException { Random rd=new Random(); Basic basic=basicList.get(rd.nextInt(84)); System.out.println(basic.getName()); return basic; }
}3 定义远程实现类,在此我把服务器的绑定一起在此类中实现,也可另外再写一个类,实现RMI绑定。(注意:一般都用Naming.rebind(),因为rebind()可以覆盖原有的服务名,省去不必要的麻烦。1099端口为默认,也可以不写)import java.rmi.Naming;import java.rmi.RMISecurityManager;import java.rmi.registry.LocateRegistry;
public class RmiHelloServer{
public RmiHelloServer() { } public static void main(String[] args) { System.setProperty("java.security.policy","Server.policy"); //创建并安装安全管理器 if(System.getSecurityManager()==null) { System.setSecurityManager(new RMISecurityManager()); }
try{ //创建远程对象 RmiHelloRemoteObj obj=new RmiHelloRemoteObj(); //启动注册表 LocateRegistry.createRegistry(2222); //奖名称绑定到对象 Naming.rebind("rmi://192.168.0.1:2222/helloObj",obj);
System.out.println("RMI服务器正在运行。。。。。。"); } catch(Exception e) { e.printStackTrace(); }
}}jdk 1.5,直接编译就ok。不需要使用rmic生成存根。运行前 unix 执行 rmiregistry &,windwows 在start rmiregistry前 set CLASSPATH=.;一下,然后再执行start rmiregistry否则出现 java.rmi.ServerException: RemoteException occurred in server thread; nested exce ption is: java.rmi.UnmarshalException: error unmarshalling arguments; nested excep tion is: java.lang.ClassNotFoundException: test.PerfectTimeI at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:385 ) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:240) at sun.rmi.transport.Transport$1.run(Transport.java:153) 可以不需要 Server.policy但是最好加上grant { permission java.net.SocketPermission "*:1000-65535","accept,connect,listen,resolve";};如果客户端过来的端口小于1000,出现java.rmi.UnmarshalException: Error unmarshaling return header; nested exception is: java.io.EOFException at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source) at sun.rmi.server.UnicastRef.invoke(Unknown Source) at sun.rmi.server.ActivatableRef.invoke(Unknown Source) at ds.rmi.server.ChatServerImpl_Stub.authenticate(Unknown Source) at ds.rmi.client.ClientUI.login(ClientUI.java:142) at ds.rmi.client.ClientUI.start(ClientUI.java:272) ...Caused by: java.io.EOFException at java.io.DataInputStream.readByte(Unknown Source) ... 8 more如果没有权限,会出现Error:java.security.AccessControlException: access denied(java.net.SockerPermission 127.0.0.1:1099 connect,resolve) 程序里面是没有表明有这样的一个端口被使用的,出现这个异常表明运行服务器权限配置有问题。 要知道对于RMI的C/S之间通信,就像Applet和WebServer之间通信一样,是要受Java的安全沙箱模型约束的。缺省情况下客户端和服务器端的代码没有权限存取硬盘/访问网络等等,这些权限必须在启动客户端和服务器端程序的时候加进去。客户端import java.rmi.Naming;import java.rmi.RMISecurityManager;import java.util.Date;
public class RmiHelloClient {
public RmiHelloClient() { }
public static void main(String[] args) { System.setProperty("java.security.policy", "Client.policy"); //创建并安装安全管理器 if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try {
RmiHelloRemoteIntfc c1 = (RmiHelloRemoteIntfc) Naming.lookup("rmi://192.168.0.1:2222/helloObj"); Basic basic = c1.getBasic(323L); } catch (Exception e) { e.printStackTrace(); } System.exit(0);
}}客户端策略grant { permission java.net.SocketPermission "*:1000-9999","accept,connect,listen,resolve";}; |
|
|