2008-10-22 18 views
1

我的启用RMI的应用程序似乎在泄露套接字。我有一个Java应用程序通过RMI提供服务。它使用在Linux上运行的Java SE 1.6 RMI实现。我观察到的问题是,如果客户端使用注册表获取对Remote对象的引用,然后突然断开连接(断电,拔掉电缆等),服务器将保持套接字打开。我希望在客户的租约到期后清理RMI实现,但这不会发生。在服务器上,当租约到期时调用Remote对象的unreferenced()方法,但套接字在netstat中始终以“ESTABLISHED”状态无限期地可见。租约到期后Java RMI未关闭套接字

由于我们无法强制客户端进入任何特定行为,因此在几天后,我们在Linux发行版中达到默认限制1024(对于打开文件描述符),导致服务器无法打开任何新套接字或文件。我想过TCP keepalive,但是由于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; 
    } 
    . 
    . 
    . 
} 
+0

好的解决办法;你应该输入它作为答案,以便我可以投票! – erickson 2008-10-29 18:07:34

+0

为什么你更喜欢它到MySocketFactory?你的项目有什么优势? – 2008-11-06 12:06:41

回答

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

Socket.setSocketImplFactory(youFactoryDemandingKeepAlive); 

,然后只用RMI。

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

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