1

我启用 RMI 的应用程序似乎正在泄漏套接字。我有一个通过 RMI 提供服务的 Java 应用程序。它使用在 Linux 上运行的 Java SE 1.6 RMI 实现。我观察到的问题是,如果客户端使用注册表获取对我的远程对象的引用,然后突然断开连接(断电、拔掉电缆等),服务器会保持套接字打开。我希望 RMI 实现在客户端的租约到期后进行清理,但这并没有发生。在服务器上,unreferenced()当租约到期时调用我的远程对象的方法,但套接字在 netstat 中无限期地处于“ESTABLISHED”状态。

由于我们无法强制客户端执行任何特定行为,因此几天后,我们的 Linux 发行版中的打开文件描述符达到了默认限制 1024,导致服务器无法打开任何新的套接字或文件。我考虑过 TCP keepalives,但由于 RMI 正在抽象出网络层,所以在建立连接后我无法访问实际的服务器套接字。

有没有办法强制 RMI 层清理绑定到具有过期租约的客户端连接的套接字?

更新:我使用的解决方案类似于选择的答案,但使用了不同的方法。我使用了一个自定义套接字工厂,然后将 createServerSocket() 返回的 ServerSocket 实例包装在一个透明包装器中,该包装器传递所有方法,除了 accept()。在 accpet 方法中,keepalives 在套接字返回之前启用。

public class KeepaliveSocketWrapper extends ServerSocket
{
    private ServerSocket _delegate = null;
    public KeepaliveSocketWrapper(ServerSocket delegate)
    {
        this._delegate = delegate;
    }

    public Socket accept() throws IOException
    {
        Socket s = _delegate.accept();
        s.setKeepAlive(true);
        return s;
    }
    .
    .
    .
}
4

1 回答 1

0
public class MySocketFactorySettingKeepAlive ... {
  // overwrite createSocket methods, call super.createSocket, add keepAlive
}

Socket.setSocketImplFactory(youFactoryDemandingKeepAlive);

然后只需使用 RMI。

如果我没记错的话,诀窍是在系统打开第一个套接字之前设法设置工厂——Java 不允许覆盖工厂;在最坏的情况下,使用反射来覆盖它:)))(开玩笑;会是一个黑客)

此外,您可能需要在 SecurityManager 中允许特定操作。

于 2008-10-22T23:47:42.947 回答