租约到期后Java RMI未关闭套接字 [英] Java RMI not closing socket after lease expiration

查看:76
本文介绍了租约到期后Java RMI未关闭套接字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My RMI enabled application seems to be leaking sockets. I have a Java application providing a service over RMI. It is using the Java SE 1.6 RMI implementation running on Linux. The problem I am observing is that if a client obtains a reference to my Remote object, using the Registry, and then the connection is severed abruptly (power loss, cable unplugged, etc...), the server keeps the socket open. I would expect the RMI implementation to clean up after the client's lease expires, but that is not happening. On the server, my Remote object's unreferenced() method is called when the lease expires, but the socket remains visible in netstat in the "ESTABLISHED" state indefinitely.

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

Since we are not able to force the clients into any specific behavior, after several days we are hitting the default limit, 1024 in our Linux distro, for open file descriptors, causing the server to become unable to open any new sockets or files. I thought about TCP keepalives, but since RMI is abstracting away the network layer, I don't have access to the actual server socket after the connection has been established.

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




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

Is there any way to force the RMI layer to cleanup sockets tied to client connections with expired leases?

Update: The solution I used is similar to the chosen answer, but uses a different approach. I used a custom socket factory, and then wrapped the ServerSocket instance returned by createServerSocket() in a transparent wrapper that passed all methods through, except for accept(). In the accpet method, keepalives are enabled before the socket is returned.

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不允许覆盖工厂;在最坏的情况下,使用反射覆盖它:)))(开玩笑;将是一个黑客)

The trick, if I remember right, is to manage to set the factory before the system opens first socket -- Java disallows to overwrite the factory; in worst case, use reflection to overwrite it :))) (kidding; would be a hack)

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

Also, you may need to allow specific operation in SecurityManager.

这篇关于租约到期后Java RMI未关闭套接字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆