我试图通过 RMI 调用返回一个普通的类。我的服务器拥有一个名为 GameState 的类的实例,我想通过它的方法从客户端应用程序执行操作。因此,如果 a 只是返回一个 int 或其他东西,RMI 就可以正常工作,但是当尝试返回 GameState(它是 GameServer java 文件中定义的类)时,会发生以下错误(游戏状态未声明为 public、protected 或 private):
线程“main”java.lang.IllegalAccessError中出现异常:尝试从类$Proxy0访问类GameState 在 $Proxy0.getGameState(来源未知) 在 GameClient.login(GameClient.java:204) 在 GameClient.main(GameClient.java:168)
所以,我猜客户端应用程序知道 GameState 的外观,但没有任何访问权限?
我尝试在自己的文件中将 GameState 设为公共(public)类,但是不同的连接客户端应用程序会获得各自的 GameState,因此似乎无法从服务器获取它。
以下是一些我认为相关的代码:
远程接口(interface):
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 来完成这一切,并且基于我对 eclipse 中的 RMI 的了解,rmic 以及不再需要的东西,我是对的吗?
有人有什么想法吗?
提前致谢!
最佳答案
我认为这不是权限问题。我无法从上面的代码中确定,但我认为这是一个代码库问题。您是否也在客户端配置了代码库?
要反序列化 GameState
类,客户端需要能够加载类定义。该定义位于服务器实现中,而不是接口(interface)中。通常,服务器实现不应编译到客户端的类路径,只有接口(interface)应该编译到客户端的类路径。我不完全确定,因为在您的解决方案中,由于 GameState
,接口(interface)似乎依赖于实现,顺便说一句,这不是一个好主意。无论如何,尝试将代码库配置添加到您的 VM-args 中。假设您在本地主机上执行所有操作,它应该如下所示:
-Djava.rmi.server.codebase=file:${workspace_loc}/PROJECT-NAME/bin/
其中 ${workspace_loc}
是工作区的绝对路径,PROJECT-NAME
是服务器项目的名称。 Eclipse 将自动解析 ${workspace_loc}
,因此您只需设置 PROJECT-NAME
附带说明:如果您以这种方式实现,GameState
对象将传输到客户端并在客户端上执行,对服务器的执行没有任何影响。这真的是你想要的吗?如果希望 GameState 实例在服务器端执行,GameState 还需要实现 Remote,而不是 Serialized >,并且在将其 stub 传输给客户端时需要将其导出。
最后,正如您所说,从 Java 1.5 开始您不需要使用 rmic
关于java - 通过 RMI 调用返回类实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9211790/