当前位置: 首页 > 知识库问答 >
问题:

Rmi客户端未使用代码库

宋鸿德
2023-03-14

我已经为rmi编程了一段时间,一个月后,我仍然被困在一个棘手的问题上。我想从服务器向客户端发送一个序列化对象,我想让客户端从服务器代码库下载这个对象的类。如果客户端的类路径中没有对象的类,我就无法让它工作。以下是我一直在做的:

我有一个ClientLoader要求一个ClientPlayer到一个AuthServerClientLoader也应该下载类ClientPlayer并动态加载它。

这是身份验证服务器,它应该创建一个对象ClientPlayer(或ClientAdmin),并将其返回给ClientLoader。(为了简洁起见,我省略了接口;无论如何,AlfaBetaInt意味着Beta实现它并Alfa使用它)

public class AuthServer extends UnicastRemoteObject implements LoaderAuthInt{

    private static MasterServer master;

    public AuthServer() throws RemoteException{
        super();
    }

    public Runnable login(String username, String password) throws RemoteException{
    System.out.println("Requested login with username '" + username + "' and password '" + password + "'");
    if(password.equals("admin"))
        return (Runnable)(new ClientAdmin());
    else

        return (Runnable)(new ClientPlayer(username, (PlayerMasterInt)master));
}

    public static void main(String[] args){

        if(System.getSecurityManager() == null)
        System.setSecurityManager(new RMISecurityManager());

        String port = args[0];

        System.out.println("Current codebase:" + System.getProperty("java.rmi.server.codebase"));

        try{
            master = new MasterServer();//create master server
            System.out.println("MasterServer creato.");

            AuthServer auth = new AuthServer();//create auth server
            System.out.println("AuthServer created.");
            Naming.rebind("//:" + port + "/authServer", (LoaderAuthInt)auth);//rebind auth server
            System.out.println("AuthServer rebinded.");
        }catch(Exception e){
            System.err.println(e);
            System.exit(1);
        }
    }
}

这是ClientLoader,它应该从服务器下载ClientPlayer(对象和类)并运行它。

public class ClientLoader{

    public static void main(String[] args){
        if(System.getSecurityManager() == null)
        System.setSecurityManager(new RMISecurityManager());

    Console console = System.console();

    String host = args[0];

    try{
                    //check to see if Server is registered in rmiregistry
        String[] lista = Naming.list("//" + host );
        for( int i = 0; i < lista.length; i = i+1)
            System.out.println(lista[i]);
            //look up the client
        LoaderAuthInt authServer = (LoaderAuthInt)Naming.lookup("//" + host + "/authServer");
        System.out.println("Lookup succesful.");
        if( authServer != null)
            System.out.println("authServer != null.");
        //RUN THE CLIENT!
        Runnable client = authServer.login(console.readLine("Username: "), new String(console.readPassword("Password: ")));

        if(client == null)
            System.err.println("Login not valid");
        else
            client.run();

        System.out.println("Bye bye");
    }catch(Exception e){
        System.err.println(e);
        System.exit(1);
    }
}
}

这是应该从AuthServer发送到ClientLoader的对象:

public class ClientPlayer implements Runnable, Serializable, GamePlayerInt{

private String username;
private PlayerMasterInt master;

public ClientPlayer(String username, PlayerMasterInt master){
    this.username = username;
    this.master = master;
}

public void run(){
    Console console = System.console();

    System.out.println("I'm a succesfully authenticated ClientPlayer!");
}catch(RemoteException e){
            System.err.println(e);
                System.exit(1);
        }
    }
}

public String getUsername() throws RemoteException{
    return username;
}
}

下面是启动服务器的脚本:请注意,我确实指定了代码库,并且将属性useCodeBaseOnly设置为false

if [ "$1" == "" -o "$2" == "" ]; then
    echo "usage: $0 <ip> <port number>"
else
java    -Djava.rmi.server.codebase=http://$1:8000/ \
        -Djava.rmi.server.hostname=$1 \
        -Djava.security.policy=policy \
        -Djava.rmi.server.useCodebaseOnly=false \
        card.AuthServer $2
fi

下面是我如何启动ClientLoader:再次,我设置了代码库和useCodeBaseOnly

if [ "$1" == "" -o "$2" == "" ]; then
    echo "usage: $0 <ip> <port>"
else
    java    -Djava.security.policy=policy \
        -Djava.rmi.server.useCodebaseOnly=true \
        -Djava.rmi.server.codebase=http://$1:8000/ \
        card.ClientLoader "$1:$2"
fi

服务器运行正常;我在8000端口有一个http服务器,在2378端口有一个RMI注册表。客户端加载程序正在运行。。。准精细:rmiregistry上的方法list()显示绑定的服务器,服务器的查找工作正常,我可以从服务器下载客户端,但当我运行它时,我得到一个ClassNotFoundException

    java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
java.lang.ClassNotFoundException: card.ClientPlayer (no security manager: RMI class loader disabled)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:196)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
at com.sun.proxy.$Proxy0.login(Unknown Source)
at card.ClientLoader.main(ClientLoader.java:26)
Caused by: java.lang.ClassNotFoundException: card.ClientPlayer (no security manager: RMI class loader disabled)
at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:395)
at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:185)
at java.rmi.server.RMIClassLoader$2.loadClass(RMIClassLoader.java:637)
at java.rmi.server.RMIClassLoader.loadClass(RMIClassLoader.java:264)
at sun.rmi.server.MarshalInputStream.resolveClass(MarshalInputStream.java:222)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1610)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1515)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:324)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:173)
... 4 more

我怀疑ClientLoader没有使用正确的代码库。。。非常感谢您的帮助!!

编辑:我按照建议向客户端启动脚本添加了-Djava.security.manager...

Exception in thread "main" java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "writeFileDescriptor")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:372)
at java.security.AccessController.checkPermission(AccessController.java:559)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.SecurityManager.checkWrite(SecurityManager.java:954)
at java.io.FileOutputStream.<init>(FileOutputStream.java:244)
at java.io.Console.<init>(Console.java:566)
at java.io.Console.<init>(Console.java:92)
at java.io.Console$2.console(Console.java:540)
at java.lang.System.console(System.java:211)
at card.ClientLoader.main(ClientLoader.java:14)

请注意,我确实有策略文件(授予AllPersion)!选项-Djava.security.manager是否改变策略配置?

编辑:策略文件中有一个输入错误。[允许我讨厌java rmi吗?]因此,回到ClassNotFoundException,尽管风格略有不同:

java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: card.ClientPlayer
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:196)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
at com.sun.proxy.$Proxy0.login(Unknown Source)
at card.ClientLoader.main(ClientLoader.java:25)
Caused by: java.lang.ClassNotFoundException: card.ClientPlayer
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.rmi.server.LoaderHandler$Loader.loadClass(LoaderHandler.java:1208)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:270)
at sun.rmi.server.LoaderHandler.loadClassForName(LoaderHandler.java:1221)
at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:454)
at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:185)
at java.rmi.server.RMIClassLoader$2.loadClass(RMIClassLoader.java:637)
at java.rmi.server.RMIClassLoader.loadClass(RMIClassLoader.java:264)
at sun.rmi.server.MarshalInputStream.resolveClass(MarshalInputStream.java:222)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1610)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1515)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:324)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:173)
... 4 more

有什么想法吗?我真的很难让它工作。。。

共有1个答案

和和裕
2023-03-14

如果更靠近堆栈跟踪,您将看到答案已经给出:

没有安全管理器:RMI类加载程序已禁用

为了支持通过RMI下载类,必须安装SecurityManager。最简单的方法系统。setSecurityManager(新的SecurityManager())

但是,当然,您必须编辑策略,以允许您的代码执行您想要执行的操作。

→编辑:我明白了,看起来你已经这么做了,但只是忘记了-Djava。安全命令行上的管理器选项。使用此选项的效果与上面的代码片段相同,它使用策略文件安装默认的SecurityManager

或者,您可以实现自己的SecurityManager。出于测试目的,很容易实现一个SecurityManager,只允许所有内容,尽管这不推荐用于生产代码。

 类似资料:
  • 我正在尝试使用RMI客户机-服务器通信。我编写了以下类/接口: > 接口远程接口扩展远程 类HelloStub扩展UnicastRemoteObject实现远程接口 类服务器,我绑定了远程obj 将客户端分类如下: 我不明白为什么我必须使用interface RemoteInterface进行查找?我不能使用HelloSub类吗,它是真正的远程obj? 谢谢,再见。

  • 问题内容: RMI是否自己处理多个客户端?即 是否可以同时使用多个客户端的服务器功能? 如果没有,我该怎么做? 如果是,它如何工作?每次 调用 都会创建一个新线程吗?如果一个客户端阻止了该功能,那么下一个客户端会发生什么?等等 问题答案: 是 这个怎么运作?每次调用都会创建一个新线程吗?如果一个客户端阻止了该功能,那么下一个客户端会发生什么?等等 它为每个客户端连接创建一个线程。 如果一个客户端调

  • 问题内容: 我目前正在Eclipse中使用GWT 2.0用Java编写Web应用程序。我想知道是否可以在GWT应用程序的 客户端 代码中使用Gson库。 __ 如果有办法,请告诉我如何… 谢谢! 问题答案: 不完全是您写的内容,但我想您的意思是如何在GWT代码中序列化/反序列化JSON? 在GWT 2.1.1中,您可以使用GWT AutoBean框架 看到在文章的底部有它神奇的代码… 即使使用继承

  • 我的项目是客户端/服务器,客户端发送一个对象到服务器,服务器响应,所有这些都是通过RMI 客户项目 //接口 //我需要把它发给的班级 //客户端 //服务器项目 //接口公共接口RMI_接口扩展了远程{ //类,我将发送和接收它公共类Employee实现可序列化的{int ID; //类来保存所有接收到的对象公共类Maneger{ //服务器公共类RMI_server扩展了UnicastRemo

  • 我正在做一个正在改造/现代化的项目,其中有一个小的RMI部分,不幸的是,我以前从未与RMI合作过。 我不明白的一件事是,为什么在我最初创建RMI客户端之后,它一直调用其自定义SocketFactory构造函数。似乎每5分钟我就会看到一次调用构造函数的输出,即使客户端和服务器之间没有通信。 连接完成后,我应该做什么来清理和停止任何线程以进行持久化? 我在检查UnicastRemoteObject,也

  • 我在客户端wnat纯java RMI,因为我需要能够重新启动服务器端。