1

私はしばらく rmi をプログラミングしてきましたが、1 か月ほど経った今でも、難しい問題に悩まされています。サーバーからクライアントにシリアル化されたオブジェクトを送信したいのですが、クライアントがこのオブジェクトのクラスをサーバーのコードベースからダウンロードするようにします。クライアントのクラスパスにオブジェクトのクラスがないと、これを機能させることはできません。これが私がやってきたことです:

に をClientLoader求めてClientPlayerAuthServerます。のクラスClientLoaderもダウンロードして動的にロードする必要があります。ClientPlayer

これは認証サーバーで、オブジェクトClientPlayer(またはClientAdmin) を作成し、これを に返しClientLoaderます。(簡潔にするために、インターフェイスは省略します。とにかく、それを実装して使用することをAlfaBetaInt意味します)BetaAlfa

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 に 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)

AllPermissionポリシー ファイル (許可)があることに注意してください。いずれにせよ、オプションは-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

何か案が?私はこれを機能させるのに本当に苦労しています...

4

1 に答える 1