我启用RMI的应用程序似乎漏掉了套接字。我有一个Java应用程序提供RMI服务。它使用在Linux上运行的Java SE 1.6 RMI实现。我观察到的问题是,如果客户端使用注册表获取对我的Remote对象的引用,然后突然切断连接(掉电,拔掉电缆等等),服务器会保持套接字打开。我希望在客户的租约到期后RMI实施能够清理,但事实并非如此。在服务器上,当租约到期时,我的Remote对象的 unreferenced()方法被调用,但是套接字在netstat中仍然可以在“ESTABLISHED”中看到。无限期地陈述。

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

有没有办法强制RMI层清除与过期租约绑定到客户端连接的套接字? 点击 点击 更新:我使用的解决方案与所选答案类似,但采用了不同的方法。我使用了一个自定义套接字工厂,然后将createServerSocket()返回的ServerSocket实例包装在一个透明的包装器中,该包装器传递了所有方法,但accept()除外。在accpet方法中,在返回套接字之前启用了Keepalive。

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;
    }
    .
    .
    .
}
有帮助吗?

解决方案

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

Socket.setSocketImplFactory(youFactoryDemandingKeepAlive);

然后只使用RMI。

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top