我启用 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;
}
.
.
.
}