2

我正在使用 RMI 为所有网络通信开发 Java 游戏。RMI 允许我在我的服务器上调用方法,但这对我来说还不够。我还希望服务器能够在连接的客户端之间传播消息。

我的客户查找服务器(它的接口扩展了 Remote)并在其上注册。它允许服务器知道谁连接了。我的客户还实现了一个扩展 Remote 的接口。这是我的代码的一部分:

接口声明:

public interface IServer extends Remote {
    void connect(IClient Client) throws RemoteException, ExistingItemException;
    //...
}

public interface IClient extends Remote {
    public void notify(Notification Notification) throws RemoteException;
    //...
}

服务器端:

//int RMIPort = 1099, ServerPort = 1100;
IServer Server = new RMIServer();
IServer Proxy = (IServer) UnicastRemoteObject.exportObject(Server, ServerPort);
LocateRegistry.createRegistry(RMIPort).rebind("//" + LocalIP + ":" + 
        RMIPort + "/xxx", Proxy);

客户端:

//Sets the local reference to IServer and creates the IClient
setInstance(new Client(Login, (IServer) LocateRegistry.getRegistry(RemoteIP).
        lookup("//" + RemoteIP + ":" + RMIPort + "/xxx")));
//Gets the IClient and makes it available for the IServer to call notify(...)
Proxy.connect((IClient) (UnicastRemoteObject.exportObject(getInstance(), 0)));

该解决方案在本地有效,但在我尝试通过 Internet 使用时无效。

我已经设置了我的路由器以将我的计算机暴露给一个固定的 IP 地址并转发 1099 和 1100 端口。此解决方案允许其他开发人员“查找”我的服务器并获得有效且可用的代理,但不允许他们导出他们的 IClient。似乎 JVM 尝试将对象导出到其本地网络,并且执行在此处停止。

因此,我尝试-Djava.rmi.server.hostname=my-external-IP为我的服务器和远程客户端传递 JVM 参数。这样做,exportObject 会ConnectException向远程 ip 而不是本地 ip 抛出一个。

4

3 回答 3

5

忘了它。在 Internet 上使用回调需要每个客户端配置他的防火墙/NAT 框/任何允许入站连接和可能的端口转发的东西。其中许多根本无法配置,其中许多是由网络管理员运行的,他们只是不会这样做。

注意,您还必须在固定端口上导出。

于 2013-04-28T22:02:44.560 回答
2

有一个替代方案:

http://dev.root1.de/projects/simon/wiki#Why-SIMON-is-better-than-

该协议与 RMI 不兼容,但用法几乎相同。从 RMI 更改为 SIMON 通常并不难。我从用户那里听说切换到 SIMON 只需 30 分钟。

于 2014-08-18T07:53:31.407 回答
0

您可能会考虑使用 RMI 以外的替代解决方案,因为我相信它是为Intranet应用程序(即本地网络中的企业应用程序)而不是 Internet 设计的。

我建议在客户端和服务器之间使用长时间运行的 TCP 连接,以便在服务器想要回传的任何时候它只是将消息推送到该连接。

在这种情况下,启动连接将始终是客户端任务。这与邮件客户端连接 imap 或 pop3 服务器的方式非常相似。

于 2013-04-28T22:11:13.613 回答