Возврат экземпляра класса через вызов RMI - PullRequest
1 голос
/ 09 февраля 2012

Я пытаюсь вернуть нормальный класс через вызов RMI.Мой сервер содержит экземпляр класса GameState, над которым я хочу выполнять действия с помощью его методов из клиентского приложения.Таким образом, RMI работает нормально, если просто вернуть int или что-то, но при попытке вернуть GameState, который является классом, определенным в Java-файле GameServer, возникает следующая ошибка (состояние игры объявляется ни открытым, ни защищенным, ни закрытым):

Исключение в потоке "main" java.lang.IllegalAccessError: попытка доступа к классу GameState из класса $ Proxy0 в $ Proxy0.getGameState (Unknown Source) в GameClient.login (GameClient.java:204) в GameClient.main (GameClient.java:168)

Итак, я думаю, клиентское приложение знает, как выглядит GameState, но не имеет к нему доступа?

Я пытался сделать GameState общедоступным классом вэто собственный файл, но затем различные подключающиеся клиентские приложения получают каждое свое GameState, так что, похоже, что его не получают с сервера.

Вот код, который, я думаю, имеет отношение:

Удаленный интерфейс:

import java.rmi.*;

public interface ServerInterface extends Remote
{
    public  GameState getGameState()  throws RemoteException;
}

Некоторые, если код сервера:

public class GameServer extends UnicastRemoteObject implements ServerInterface {
    /**
     * 
     */
    private static final long serialVersionUID = -6633456258968168102L;

    private final static int DEFAULT_NAMING_PORT = 9955; // TODO: IMPORTANT - change this to a group-specific number,
    // e.g., 2000 + group number. The number should be the same
    // as in GameClient.java.

    private final GameState m_state;

    public static void main(String[] args) {

            //the variables: port and host etc it configurated here, but has nothing to do with the RMI problem.

        try {
            GameServer instance = new GameServer(players);
            System.out.print("Setting up registry on "+host+":"+port+"  ... ");

            //Set up an unrestricted security manager.
            if (System.getSecurityManager() == null) {
                // Set security manager to an instance of a dynamically created
                // subclass of RMISecurityManager with the checkPermission() method overloaded
                System.setSecurityManager(
                        new RMISecurityManager() {
                            @Override
                            public void checkPermission(Permission permission) {
                            }
                        }
                );
            }

            // Create a registry for binding names (name server)
            Registry naming = LocateRegistry.createRegistry(port);
            System.out.println("done.");

            String rmiObjectName = "GeschenktServer";
            System.out.print("Binding name "+rmiObjectName+" ... ");
            naming.rebind(rmiObjectName, instance);
            System.out.println("done.");
        } catch(RemoteException e) {
                System.err.println("Could not start server: "+e);
                System.exit(-1);
            }
        }

  //the rest of the server code....

  //the GameState declared in the same file

class GameState implements java.io.Serializable {

    private static final long serialVersionUID = 545671487061859760L;

//the rest of the Game state code.

Вот часть кода клиента:

private void login() {
        try {
            System.out.println("Connecting to server on host "+m_host+".");

            // Set up an unrestricted security manager. In the server we trust.
            // See GameServer.java for code explanation.
            if (System.getSecurityManager() == null) {
                System.setSecurityManager(
                        new RMISecurityManager() {
                            @Override
                            public void checkPermission(Permission permission) {
                            }
                        }
                );
            }

            System.out.print("Locating registry on "+m_host+":"+m_port+"  ... ");
            Registry naming = LocateRegistry.getRegistry(m_host, m_port);
            System.out.println("done.");
            String name = "GeschenktServer";
            System.out.print("Looking up name "+name+" ... ");
            m_server = (ServerInterface) naming.lookup(name);
            System.out.println("done.");

            // TODO: Connect the player, i.e., register the player with the server.
            // Make sure that the player cannot register if there are already enough players.

            m_Id = m_server.getGameState().loginPlayer(m_name);  //this line is causing the error...

            if(m_Id < 0)
                System.exit(0);

            System.out.println("Server connection successful.");        
            m_window = new GameWindow(m_server, m_name, m_Id);
            m_window.run();
        } catch (Exception e) {
            System.out.println("Connection failed - "+e);
            System.exit(1);
        }
    }   
}

Я использую Eclipse, чтобы сделать все это, и основываясь на том, что у меня есть красный о RMI в Eclipse, Rmic, и этот материал больше не нужен, я прав?

Так что кто-нибудь сЕсть идеи?

Заранее спасибо!

Ответы [ 3 ]

0 голосов
/ 10 февраля 2012

попробуйте вернуть GameState, класс, определенный внутри Java-файл GameServer, возникает следующая ошибка (состояние игры не объявлены ни публичными, ни защищенными, ни частными)

Это проблема. Только класс GameServer и классы в одном пакете могут создавать экземпляры GameState. Ваш прокси-объект RMI (заглушка) Сделайте его открытым классом в своем собственном файле.

Я пытался сделать GameState общедоступным классом в своем собственном файле, но тогда разные подключающиеся клиентские приложения получают свои GameState, так что кажется, что не получить его с сервера

Это верно. Это сериализовано каждому клиенту. Если вы хотите предоставить общий доступ к одному GameState и оставить его на сервере, это должен быть сам экспортированный удаленный объект с удаленным интерфейсом , называемым GameState.

0 голосов
/ 10 февраля 2012

Причина IllegalAccessError проста:

Однако, есть большая проблема:

вы понимаете, что loginPlayer не будет делать то, что вам нравится ... GameState является копией исходного состояния. Вы хотите, чтобы GameState был Remote не сериализуемым, поэтому вы можете выполнить операцию на сервере, а не на каждом клиенте, чтобы получить бесполезную копию.

0 голосов
/ 09 февраля 2012

Я не думаю, что это проблема разрешения.Я не могу сказать наверняка из кода выше, но я бы предположил, что это проблема кодовой базы.Вы настраивали кодовую базу также на стороне клиента?

Чтобы десериализовать класс GameState, клиент должен иметь возможность загрузить определение класса.Это определение находится в реализации Сервера, а не в интерфейсе.Обычно реализация сервера не должна компилироваться в путь к классу клиента, а только в интерфейсе.Я не совсем уверен, так как в вашем решении интерфейс, кажется, зависит от реализации из-за GameState, что, кстати, не очень хорошая идея.В любом случае, попробуйте добавить конфигурацию кодовой базы в ваши VM-аргументы.Предполагая, что вы выполняете все на локальном хосте, это должно выглядеть так:

-Djava.rmi.server.codebase=file:${workspace_loc}/PROJECT-NAME/bin/

Где ${workspace_loc} - абсолютный путь к вашей рабочей области, а PROJECT-NAME - имя проекта сервера.Eclipse разрешит ${workspace_loc} автоматически, поэтому вам нужно всего лишь установить PROJECT-NAME

. Примечание: если вы реализуете его таким образом, объект GameState передается на клиентскую сторону ивыполняется на клиенте, никак не влияя на выполнение сервера.Это действительно то, что вы хотите?Если вы хотите, чтобы экземпляр GameState выполнялся на стороне сервера, GameState также должен реализовывать Remote, а не Serializable, и вам необходимо экспортировать его при передаче его заглушки клиенту.

Наконец, как вы правильно сказали, вам не нужно использовать rmic начиная с Java 1.5

...