一个简单的RMI例子不能运行,请指点指点(100分)

  • 主题发起人 主题发起人 coobo
  • 开始时间 开始时间
C

coobo

Unregistered / Unconfirmed
GUEST, unregistred user!
浏览器显示:
error:java.lang.UnsatisfiedLinkError:java/security/AccessController.doPrivileged possible cause....(后面的看不到了)
这是什么错误?是远程对像没有注册成功吗?
另外:远程对像在什么时候注册?是在调用它的时候,还是手工加入?
《JAVA服务器程序设计》第十一章 RMI与Servlet 中第一个例子
我想在主机上是不是有点问题,HelloWorldImpl 中我想后将host="zhao" 和host="zhao:8080"都不行;
书上有这么一段话:
在URL中可以加一个端口号,如/myhost:1234/HelloWorldServer。注册表的缺省端口是1099。如服务器创建的注册表不在缺省的端口1099上,在URL中就要指定端口号。
8080应该叫什么端口(http?),也是注册表端口吗?
看了下面的贴子,我将jb的RMIRegistry选中,出错如下
java.rmi.NotBoundException: HelloWorldServer
==================
package examples.helloworld;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface HelloWorld extends Remote {
String sayHelloWorld() throws RemoteException ;
}
===================
package examples.helloworld;
import java.rmi.* ;
import java.rmi.server.UnicastRemoteObject;
public class HelloWorldImpl extends UnicastRemoteObject implements HelloWorld {
private String name ;
public HelloWorldImpl(String s) throws RemoteException {
super();
name = s ;
}
public String sayHelloWorld() throws RemoteException{
return "Hello World!" ;
}
public static void main(String[] args) {
String host = "zhao:8080" ;
String serverName = "HelloWorldServer" ;
建并安装一个安全管理员
System.setSecurityManager(new RMISecurityManager());
try {
HelloWorldImpl obj = new HelloWorldImpl(serverName);
远程对像HelloWorldServer与该对象的一个指针捆绑在一起
Naming.rebind("//" + host + "/" + serverName,obj) ;
System.out.println("HelloWorldServer bound in registry") ;
} catch (Exception e) {
System.out.println("HelloWorldImpl err:" + e.getMessage());
e.printStackTrace();
}
}
}
========applet========
package examples.helloworld;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.rmi.*;
public class HelloWorldApplet extends Applet {
String Remotemessage = "" ;
public String getParameter(String key, String def) {
return isStandalone ? System.getProperty(key, def) :
(getParameter(key) != null ? getParameter(key) : def);
}
public void init() {
String host = getCodeBase().getHost() ;
try {
HelloWorld obj = (HelloWorld)Naming.lookup("//" + host + "/HelloWorldServer") ;
Remotemessage = obj.sayHelloWorld();
}
catch(Exception e) {
e.printStackTrace();
}
}
public void paint(Graphics g) {
g.drawString(Remotemessage,25,50);
}
}
 
将jb的RMIRegistry选中,将String host = "zhao:8080"
改成String host = "zhao" ,创建一个policy文件。
在project属性中将-Djava.security.policy
和-Djava.rmi.server.codebase设好,就可以了。
创建一个policy文件、java.security.policy和java.rmi.server.codebase
的设置看下面的贴子。
 
这个问题解决了,可以运行了。:)贵我开始没细看下面的贴子:P
另外问问:
当系统完成后,这些RMI(应该怎么称呼?servlet?)要每次在服务器启动时加载呢(要把他们加到自动批处理文件中运行吗?),
还是注册一次就一切ok了?
我是把所有能用到得远程方法都写到一个class中好,还是写成几个server分别加载,有资源利用方面
和效率的考虑吗?通常是怎么做的?
说用rmic编译后会产生...Impl_Stub.class和...Impl_Skel.class两个文件,用JB没有产生后一个文件
也能运行,怎么不一致?就是不需要吗?
 
1.这些Remote object需要每次在服务器启动时加载并注册。
2。是不是是把所有能用到得远程方法都写到一个class中,与你的内容有关,
相关的logic就可以写成一个class.
3.java2的RMI不需要skel.
 
当然,可以把这些Remote object写成自动激活对象,就不要每次都加载
只需要在有client访问时激活。
 
>>当然,可以把这些Remote object写成自动激活对象,就不要每次都加载
怎么写呢?
 
上次我发的一个帖子问了个rmi的问题,对于jbuilder4里的例子能运行起来,对于简单的
rmi程序也可以。
但是我自己写的rmi仍然存在问题:我写的一个使用了com.borland.dx.sql.dataset包的
程序却总是报错:
java.rmi.ServerError: Error occurred in server thread;
nested exception is:
java.lang.NoClassDefFoundError: com/borland/dx/sql/dataset/QueryDataSet
我在jbuilder里已经把这个包加入到project里,而且再三看了classpath,确实带了这个包的路径
我又用java命令行运行过,都不行。
相反,如果我在那个简单的例子程序里加入这个包,再用包里的类就顺利运行。
我比较过两者的命令行,简直是一模一样。
真是想破我的脑袋了。
能帮我解决的大虾,一定再给分。
 
刚刚查了jdk1.3的帮助,把包的路径加到codebase里,就行了。
唉,为什么classpath不管用呢?
 
eguy 感到很累吗 :)
给说说自动激活(注册)RMI远程对象的书写步奏和方法吧。
 
>>相反,如果我在那个简单的例子程序里加入这个包,再用包里的类就顺利运行。
to yuanjun:你的这个简单的例子不是在JB里吧。
to all:自动激活(注册)RMI远程对象的书写步奏和方法
(其实帮助里都有,大家为什么还要问呢?):
(远程接口和client的编写就省略了,因为和一般的RMI是一样的)
一、创建实现类
步骤 1:
在实现类中进行相应的导入
import java.rmi.*;
import java.rmi.activation.*;
步骤 2:
利用 java.rmi.activation.Activatable 对类进行扩展
public class ActivatableImplementation extends Activatable
implements examples.activation.MyRemoteInterface {
步骤 3:
在实现类中声明一个带两个参数的构造函数
public ActivatableImplementation(ActivationID id, MarshalledObject data)
throws RemoteException {
// 在激活系统中注册对象
// 然后在匿名端口导出
super(id, 0);
}
步骤 4:
实现远程接口方法
public Object callMeRemotely() throws RemoteException {
return "Success";
}
二、创建“设置”类
设置类将可激活类的信息传到 rmid,在 rmiregistry 中注册远程引用
(可激活类的 stub 类的实例)和标识符(名称),然后退出。
创建设置类的过程有七步:
步骤 1:
在设置类中进行相应的导入
import java.rmi.*;
import java.rmi.activation.*
import java.util.Properties;
步骤 2:
安装 SecurityManager
System.setSecurityManager(new RMISecurityManager());
步骤 3:
创建 ActivationGroup 实例
Properties props = new Properties();
ActivationGroupDesc.CommandEnvironment ace = null;
ActivationGroupDesc exampleGroup = new ActivationGroupDesc(props, ace);
ActivationGroupID agi = ActivationGroup.getSystem().registerGroup(exampleGroup);
ActivationGroup.createGroup(agi, exampleGroup, 0);
步骤 4:
创建 ActivationDesc 实例
激活描述符的工作是为 rmid 提供创建实现类的新实例所需的所有信息。
注意:为了在系统中运行此代码,需要将文件 URL 位置改为在系统中安装示例源代码的目录位置。
// “location”字符串指定该对象被请求
// (激活)时类定义所在的 URL。
// 不要忘记 URL 后面跟的斜杠,否则将找不到
// 类。
String location = "your file location";
// 创建传给 ActivationDesc 构造函数的参数的其余
// 部分
//
MarshalledObject data = null;
// ActivationDesc 构造函数的第二个参数将被用来
// 对该类进行唯一标识,其位置是 URL 格式的字符
// 串 location 的相对位置。
//
ActivationDesc desc = new ActivationDesc
("ActivatableImplementation", location, data);
步骤 5:
声明远程接口的实例并在 rmid 中注册激活描述符
MyRemoteInterface mri = (MyRemoteInterface)Activatable.register(desc);
System.out.println("Got the stub for the ActivatableImplementation");
步骤 6:
将 Activatable.register 方法返回的 stub 与 rmiregistry 中的名称绑定
Naming.rebind("ActivatableImplementation", mri);
System.out.println("Exported ActivatableImplementation");
步骤 7:
退出设置应用程序
System.exit(0);
三、编译和运行代码 步骤 1:
编译远程接口、实现、客户机和设置类
% javac -d . MyRemoteInterface.java
% javac -d . ActivatableImplementation.java
% javac -d . Client.java
% javac -d . Setup.java
步骤 2:
在实现类上运行 rmic
% rmic -d . ActivatableImplementation
步骤 3:
启动 rmiregistry
步骤 4:
启动激活守护进程 rmid
rmid
步骤 5:
运行设置程序
运行设置程序,将 codebase 属性设置为实现 stub 的位置。
服务器的输出应如下所示:
Got the stub for the ActivatableImplementation
Exported ActivatableImplementation
步骤 6:
运行客户机
客户机的输出应如下所示:
Got a remote reference to the object that extends Activatable.
Making remote call to the server
Returned from remote call
Result: Success

 
我们这些笨鸟让eguy大侠操劳,真是过意不去,还都怪我笨,昨天的好用的例子,今天就罢工了:(
还叽哩咕噜说了一大堆令我不知该干点什么的符号:
HelloWorldImpl err:Connection refused to host: zhao;
nested exception is:
java.net.ConnectException: Connection refused: no further information
java.rmi.ConnectException: Connection refused to host: zhao;
nested exception is:
java.net.ConnectException: Connection refused: no further information
java.net.ConnectException: Connection refused: no further information
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:125)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:112)
at java.net.Socket.<init>(Socket.java:269)
at java.net.Socket.<init>(Socket.java:98)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:29)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:124)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:497)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:194)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:178)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322)
at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
at java.rmi.Naming.rebind(Naming.java:165)
at examples.helloworld.HelloWorldImpl.main(HelloWorldImpl.java:35)
部分代码:
public static void main(String[] args) {
String host = "zhao" ;//我的机器名
String serverName = "HelloWorldServer" ;
//创建并安装一个安全管理员
System.setSecurityManager(new RMISecurityManager());
try {
HelloWorldImpl obj = new HelloWorldImpl(serverName);
//把远程对像HelloWorldServer与该对象的一个指针捆绑在一起
Naming.rebind("//" + host + "/" + serverName,obj) ;
System.out.println("HelloWorldServer bound in registry") ;
} catch (Exception e) {
System.out.println("HelloWorldImpl err:" + e.getMessage());
e.printStackTrace();
}
jb的例子也不中了。
 
coobo:检查一下rmiregistry开了吗,再看看vm的参数设置。
把你vm的参数设置贴出来看看吧。
 
to eguy:
我写的例子都是在jbuilder下的。
看jdk的文档,如果远程方法返回值是一个非java类库的对象,
要在codebase添加它的包路径。估计原来是这么出错的,只不过我在简单例子里为什么不用加包路径到codebase里就能行呢?
当然,加进去后所有东西都变得很正常了。
 
呵呵,真是马虎呀:不知何时注册选项被去掉了。。
另外,要使用命令行的形式来编译,首先是启动rmiregistry.exe
是直接运行它呢,还是用:javaw rmiregistry (start rmiregistry) 呢?
我试了几种方式都不行。
 
用start rmiregistry就行了,当然你机器里要把jdk的路径加进去了。
 
这是实现类中的一个返回ResultSet 类型的方法,但执行到 Class.forName(sDBDriver);
时为什么会出错?我用的是Access库,放在d:/RMI/Access-Data/;
工程文件*.jpr放在d:/RMI/
好像还是安全问题:
java.security.AccessControlException: access denied (java.lang.RuntimePermission accessClassInPackage.sun.jdbc.odbc )
我的.policy文件内容:
grant {
// allows anyone to listen on un-privileged ports
permission java.net.SocketPermission "*:1024-65535", "listen,accept,connect";
};
我需要在.policy文件中加东西吗?
针对不同的数据库一样吗?
 
这个问题解决了,在policy中加入
permission java.lang.RuntimePermission "accessClassInPackage.sun.jdbc.odbc";
permission java.util.PropertyPermission "file.encoding" , "read" ;
-------------------
yuanjun:你用RMI返回ResultSet了吗?我怎么返回不了?
java.rmi.UnmarshalException: error unmarshalling return;
nested exception is:
java.io.WriteAbortedException: Writing aborted by exception;
java.io.NotSerializableException: sun.jdbc.odbc.JdbcOdbcResultSet
java.io.WriteAbortedException: Writing aborted by exception;
java.io.NotSerializableException: sun.jdbc.odbc.JdbcOdbcResultSet
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:429)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:232)
at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:304)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:138)
at cn.com.cbl.tableRMI.TableRMIImpl_Stub.getRS(TableRMIImpl_Stub.java:39)
at cn.com.cbl.tableRMI.AppletTable.init(AppletTable.java, Compiled Code)
at com.borland.jbuilder.runtime.AppletTestbed.startApplet(Unknown Source)
at com.borland.jbuilder.runtime.AppletTestbed.main(Unknown Source)

 
rmi的返回值要求是serializable的,ResultSet不知道是不是。
但我觉得应该是的。
我用rmi来读取远程数据库,返回值是QueryDataSet(com.borland.dx.sql.dataset.QueryDataSet)
帮助上明明写着是serializable的,但就是返回不了!!
而且一用rmi,很多本地运行好好的类就不能用了,如Database(也是在com.borland.dx.*里),
即使不是作为返回值或参数,只是作为调用函数运行时产生的一个实例也不行。
对象实例引用全部变成null了。
不知道这些类的结构是什么样子的,是不是在rmi的server端运行起来时就不能正确引用了。
 
顺手看了一下帮助(看得不是很仔细),ResultSet是个interface,没有implements serializable。
就是说,不可被序列化,那么就不能作为rmi的结果返回了。
coobo,要能解决这个问题就好了。
 
555555555,
没有人回答吗?
我来加上100分,请教各路高手:
如何将查询数据库的结果返回给客户端?除了rmi之外有什么别的办法没有?
 
后退
顶部