【发布时间】:2010-09-18 15:25:15
【问题描述】:
我启用 RMI 的应用程序似乎泄漏了套接字。我有一个通过 RMI 提供服务的 Java 应用程序。它使用在 Linux 上运行的 Java SE 1.6 RMI 实现。我观察到的问题是,如果客户端使用注册表获取对我的远程对象的引用,然后突然断开连接(断电、拔掉电缆等),服务器会保持套接字打开。我希望 RMI 实现在客户端的租约到期后进行清理,但这并没有发生。在服务器上,我的远程对象的 unreferenced() 方法在租约到期时被调用,但套接字在 netstat 中仍以“ESTABLISHED”状态无限期保持可见。
由于我们无法强制客户端执行任何特定行为,几天后我们达到了默认限制,在我们的 Linux 发行版中,打开文件描述符为 1024,导致服务器无法打开任何新套接字或文件。我考虑过 TCP keepalives,但由于 RMI 正在抽象出网络层,所以在建立连接后我无法访问实际的服务器套接字。
是否有任何方法可以强制 RMI 层清理绑定到具有过期租约的客户端连接的套接字?
更新: 我使用的解决方案与选择的答案相似,但使用了不同的方法。我使用了一个自定义套接字工厂,然后将 createServerSocket() 返回的 ServerSocket 实例包装在一个透明包装器中,该包装器传递所有方法,除了accept()。在accpet方法中,在socket返回之前开启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;
}
.
.
.
}
【问题讨论】:
-
很好的解决方案;你应该输入它作为答案,所以我可以投票!
-
为什么你更喜欢它而不是 MySocketFactory?您的项目有什么优势?
-
您将连接池与 DGC 租约混为一谈。他们不是一回事。 RMI 的 TCP 连接在可配置的空闲超时(通常为 15 秒)后由客户端关闭。 DGC 租用时间要长得多,以分钟计,但它们只影响 DGC,而不影响 TCP 连接。而RMI默认开启两端的TCP keepalive。所以你描述的情况很难理解。您确定是 RMI 连接泄漏了吗?