最近在学RMI远程调用,今天终于把《Java高级编程:JDK5》中的范例代码调试成功了,现在把我在调试中遇到的问题总结一下,有兴趣的朋友可以看一下,本程序jdk版本为1.6,平台为WinXP。
此范例主要完成一个聊天室的功能,共有四个类、一个嵌入Applet的htm网页和一个安全策略文件,分别是:
RMIChat接口
RMIChatImpl类
ChatUser类
ChatApplet类
test.htm
rmi.policy
为了更详细的叙述,下面结合代码进行讲述,具体的步骤为:
1、定义RMIChat接口
此接口实现必须扩展java.rmi.Remote接口,并且该接口中定义的方法必须抛出RemoteException,代码如下:
2,实现RMIChatImpl类
该类是实现RMIChat接口的类。它定义了在RMIChat接口中存在的每一个方法,它的主要目的是作为一个服务来连接RMIClient。此类需要注册到RMI注册表。代码如下:
这个类的main方法非常重要,他完成RMIChatImpl对象到RMI注册表的的注册,下面对其进行分析:
1、首先它设置一个用于服务器的安全管理器。可以裁剪安全管理器以适应体系结构的需要,这个简单的示例只是使用了默认的系统安全管理。
2、然后它构造一个RMIChatImpl对象,该对象将被注册到RMI注册表。
3、最后,它使用Naming.bind方法将RMIChatImpl对象绑定到注册表中的“RMIChatServer”名称上。客户端可以搜索“RMIChatSe rver”来获得一个远程RMIChatImpl对象。
注意:RMI注册表必须在上述步骤之前启动,以确保对RMI注册表的正确注册操作。下面会有体现。
3、定义ChatUser类
ChatUser类用来存储有关RMIChatImpl服务器用户的特定信息,该类是客户端和服务器端都要用到的。代码如下:
4、定义ChatApplet类
ChatApplet类是用于客户端的类,该范例中用一个Applet小程序来实现客户端的功能。ChatApplet类并不需要扩展或者实现任何特定的RMI接口或者类,我们知道RMI远程方法调用对于用户来说和调用本地类是没有任何区别的,所以客户端是一个瘦客户端。该类的代码如下:
5、下面定义test.htm网页的内容
<html>
<body>
<applet CODE=ChatApplet.class width="300" height="200" >
</applet>
</body>
</html>
6、编写策略文件,命名为rmi.policy,文件内容很简单,如下:
grant {
permission java.net.SocketPermission "*:1024-65535", "accept,connect,listen,resolve"; //(1.1)
permission java.net.SocketPermission "*:80", "accept,connect,listen,resolve"; //(1.2)
//上面两行代码也可以不要,我自己试了不要也可以,但是网上有篇文章说必须在AllPermission的基础上加这两行,不知道为什么读者可以自己试一下
permission java.security.AllPermission;
};
7、编译文件并测试
7.1将上面的五个文件放到D:/chat/文件夹下面,分别编译RMIChat.java,RMIChatImpl.java,ChatUser.java和ChatApplet.java。
7.2运行java的rmic工具,在命令提示符窗口输入“rmic RMIChatImpl”单击回车,生成对应RMIChatImpl的存根文件RMIChatImpl_Stub.class。
7.3启动RMI注册表,这一步是必须的,命令格式为start rmiregistry。
7.4运行服务器端程序RMIChatImpl,命令如下:
D:/chat> java -Djava.security.policy=file:./rmi.policy -Djava.rmi.server.codebase=file:./RMIChatImpl RMIChatImpl
7.5运行test.htm文件,测试该聊天室程序。开两个命令提示符窗口,分别输入下面的命令,然后进行聊天室验证。
D:/chat>appletviewer test.htm
如果你的Applet小程序可以成功通信,恭喜,你成功了,你已经成功的创建了一个RMI系统,并且使它正确工作了。即使你运行在同一个计算机上,RMI还是使用了你的网络堆栈和TCP/IP去进行通讯,并且是运行在三个不同的Java虚拟机上。这已经是一个完整的RMI系统。
8、问题总结
8.1问题一
刚开始反复编译,出现如下错误
D:/chat> java -Djava.security.policy=file:./rmi.policy -Djava.rmi.server.codebase=file:./RMIChatImpl RMIChatImpl
RMIserver erroraccess denied (java.net.SocketPermission 127.0.0.1:1099 conne
esolve)
java.security.AccessControlException: access denied (java.net.SocketPermissi
27.0.0.1:1099 connect,resolve)
原因为我的rmi.policy策略文件配置有误,程序运行受到安全策略的限制。
8.2问题二
所有的类都编译成功之后,按照上面的步骤进行测试,但是每当运行RMIChatImpl的时候就报出下面的错误
上面代码可能有点儿乱,其中心意思就是RMIChatImpl_Stub.class这个文件找不到,这究竟是什么原因呢,我明明已经成功编译出了这个文件啊?通过认真思索终于找到了原因所在,如下:
刚开始我运行RMI注册表时所在目录为:C:/Documents and Settings/Administrator>rmiregistry,在此目录下,注册表的确可以顺利启动,但是它对chat目录下的程序运行根本不起作用。然后进行改正,在chat目录下运行RMI注册表,然后再运行RMIChatImpl,可以成功运行。
8.3问题三
本示例中所有的类文件都放到了一个文件夹下(chat文件夹),但实际情况是服务器端和客户端肯定不是在一个目录下的,下面将客户端和服务器端文件进行分离,进行程序测试。
在f:/根目录下创建两个文件夹chatS和chatC,分别存放服务器端和客户端的文件,chatS文件夹下的文件为RMIChatImpl.class,RMIChat.class,ChatUser.class,rmi.policy和RMIChatImpl_Stub.class文件,chatC文件夹下的文件为ChatApplet.class , ChatApplet$1.calss , ChatApplet$2.class , ChatUser.class,RMIChat.class和test.htm文件。
依照前面的测试步骤,在chatS文件夹下RMI注册表和RMIChatImpl都可顺利执行,但是在chatC文件夹下运行ChatApplet时提示我RMIChatImpl_Stub.class文件找不到,看来此文件是客户端必须的(不论Applet还是application),然后将该stub文件复制到chatC文件夹下执行,可以顺利执行。
8.4问题四
我在另一个rmi测试程序的练习中,对编译后的文件进行rmic处理时,生成的文件有两个,一个是_Stub结尾的,另一个是_Skel结尾的,二本程序之生成了一个Stub文件。我从网上找原因,有一个答案是不同版本jdk的原因,但是我是在相同的机器上测试的,这个问题还未解决,希望高手赐教。
8.5问题五
客户端程序需不需要安全策略文件呢?我自己编写了一个rmi程序,发现直接输入“java client”客户端即可顺利执行,但是该页面的http://blog.csdn.net/goleagle/archive/2009/04/25/4107853.aspx一篇文章说到,客户端需要安全策略文件才可以执行,否则会抛出异常,看来应该和具体的配置有关系。
8.6问题六
程序的发布问题,该程序客户端是Applet程序,怎样保证从浏览器端正确运行该测试程序呢?在chat目录下直接运行test.htm肯定不行,你可以试试,此时浏览器可以显示界面,但无法和服务端连接。程序该如何发布呢?我进行了如下操作:
首先,把Chat文件夹复制到Tomcat服务器的Root目录下。
然后,将Chat 文件夹下的 ChatApplet$1.class , ChatApplet$2.class , ChatApplet.class , RMIChat.class 和RMIChatImpl_Stub.class文件打包生成test.jar文件。
其次,修改test.htm文档中的内容,如下:
<html>
<body>
<applet archive=test.jar CODE=ChatApplet.class width="300" height="200" >
</applet>
</body>
</html>
最后,运行RMI注册表和RMIChatImpl,成功运行后,在IE浏览器中输入localhost:8080/chat/test.htm,单击回车,发现返回正常的Applet页面,进行连接测试,发现仍然无法成功链接到服务器端程序,这究竟是什么原因呢?
从网上找原因,有n种答案,主要就是这两种:
1.安全性限制,需要修改客户端的安全策略文件,或者运用数字签名
2.IE不支持java2
本人进行反复实验就是无法找到本质原因,希望有谁看到这篇文章能够成功解决这一问题。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/goleagle/archive/2009/04/25/4107853.aspx