【问题标题】:Java RMI not closing socket after lease expirationJava RMI 在租约到期后不关闭套接字
【发布时间】: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 连接泄漏了吗?

标签: java sockets rmi


【解决方案1】:
public class MySocketFactorySettingKeepAlive ... {
  // overwrite createSocket methods, call super.createSocket, add keepAlive
}

Socket.setSocketImplFactory(youFactoryDemandingKeepAlive);

然后只使用 RMI。

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

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

【讨论】:

  • 你可以使用一些系统属性来指定工厂类名(忘记名字了)。
  • 找不到该属性; Google 只知道 SSL 和 LDAP 变体
  • @ddimtrov 不,你不能。没有这样的财产。如果您有反证,请提供。但是 RMI 中的每个远程对象都有客户端和服务器套接字工厂。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-09
  • 2011-01-20
  • 1970-01-01
  • 2012-06-18
  • 2014-03-01
  • 1970-01-01
相关资源
最近更新 更多