Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 通过RMI调用返回类实例_Java_Permissions_Rmi - Fatal编程技术网

Java 通过RMI调用返回类实例

Java 通过RMI调用返回类实例,java,permissions,rmi,Java,Permissions,Rmi,我试图通过RMI调用返回一个普通类。我的服务器持有一个名为GameState的类的实例,我希望通过它的方法从客户端应用程序对该类执行操作。因此,如果仅返回int或其他内容,RMI可以正常工作,但当尝试返回GameState(GameServer java文件中定义的类)时,会发生以下错误(游戏状态声明为public、protected或private): 线程“main”java.lang.IllegalAccessError中出现异常:试图从类$Proxy0访问类GameState 位于$Pr

我试图通过RMI调用返回一个普通类。我的服务器持有一个名为GameState的类的实例,我希望通过它的方法从客户端应用程序对该类执行操作。因此,如果仅返回int或其他内容,RMI可以正常工作,但当尝试返回GameState(GameServer java文件中定义的类)时,会发生以下错误(游戏状态声明为public、protected或private):

线程“main”java.lang.IllegalAccessError中出现异常:试图从类$Proxy0访问类GameState 位于$Proxy0.getGameState(未知源) 登录(GameClient.java:204) 位于GameClient.main(GameClient.java:168)

所以,我猜客户端应用程序知道游戏状态是什么样子,但没有任何访问权限

我曾尝试在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);
        }
    }   
}
private void login(){
试一试{
System.out.println(“连接到主机上的服务器”+m_主机+”;
//在我们信任的服务器上设置一个无限制的安全管理器。
//有关代码解释,请参见GameServer.java。
if(System.getSecurityManager()==null){
System.setSecurityManager(
新的RMISecurityManager(){
@凌驾
公共无效检查权限(权限){
}
}
);
}
System.out.print(“在“+m_主机+”上定位注册表:“+m_端口+”);
注册表命名=LocateRegistry.getRegistry(m_主机,m_端口);
System.out.println(“完成”);
String name=“GeschenktServer”;
系统输出打印(“查找名称”+名称+”);
m_server=(ServerInterface)naming.lookup(name);
System.out.println(“完成”);
//TODO:连接播放机,即向服务器注册播放机。
//如果已经有足够的玩家,请确保该玩家无法注册。
m_Id=m_server.getGameState().loginPlayer(m_name);//此行导致错误。。。
如果(m_Id<0)
系统出口(0);
System.out.println(“服务器连接成功”);
m_window=新游戏窗口(m_服务器、m_名称、m_Id);
m_window.run();
}捕获(例外e){
System.out.println(“连接失败-”+e);
系统出口(1);
}
}   
}
我正在使用eclipse来完成这一切,基于我在eclipse中对RMI的了解,rmic和那些不再需要的东西,我是对的

有人知道吗


提前谢谢

我认为这不是权限问题。我无法从上面的代码中确定,但我认为这是一个代码库问题。您是否也在客户端配置了代码库

要反序列化
GameState
类,客户端需要能够加载类定义。此定义位于服务器实现中,而不是接口中。通常,不应将服务器实现编译到客户机的类路径,而应仅编译接口。我不完全确定,因为在您的解决方案中,由于
游戏状态
,接口似乎依赖于实现,这不是一个好主意。顺便说一句,请尝试将代码库配置添加到您的VM参数中。假设您在本地主机上执行所有操作,它应该如下所示:

-Djava.rmi.server.codebase=file:${workspace_loc}/PROJECT-NAME/bin/
其中,
${workspace\u loc}
是工作区的绝对路径,
PROJECT-NAME
是服务器项目的名称。Eclipse将自动解析
${workspace\u loc}
,因此您只需设置
项目名称

附带说明:如果以这种方式实现,则
GameState
对象将传输到客户端并在客户端上执行,对服务器的执行没有任何影响。这真的是你想要的吗?如果希望在服务器端执行
GameState
实例,
GameState
还需要实现
Remote
,而不是
Serializable
,并且在将存根传输到客户端时需要将其导出

最后,正如您正确地指出的,由于Java1.5,您不需要使用rmic

尝试返回GameState,它是在 GameServer java文件,出现以下错误(游戏状态为 声明非公共、受保护或私有)

这就是问题所在。只有GameServer类和同一软件包中的类才能创建GameState实例。您的RMI代理对象(存根)使其成为自己文件中的公共类

我曾试图在GameState自己的文件中使其成为一个公共类,但是 然后,不同的连接客户机应用程序各有自己的应用程序 游戏状态,所以看起来好像没有从服务器获取它


没错。它被序列化到每个客户端。如果您想共享一个游戏状态并将其保留在服务器上,它必须是一个导出的远程对象本身,带有一个名为GameState的远程接口。

IllegaAccessError原因很简单:
    游戏状态不是公共的

然而,还有一个更大的问题:


您知道
loginPlayer
不会做您想做的事情。。。游戏状态是原始状态的副本。您希望游戏状态为
Remote
不可序列化,因此您可以在服务器上执行操作,而不是在每个客户端上执行操作以获取无用的副本。

这没有帮助。它不是ClassNotFoundException或NoClassDefFoun