简体   繁体   English

Java RMI在租约到期后未关闭套接字

[英]Java RMI not closing socket after lease expiration

My RMI enabled application seems to be leaking sockets. 我启用了RMI的应用程序似乎正在泄漏套接字。 I have a Java application providing a service over RMI. 我有一个Java应用程序,它通过RMI提供服务。 It is using the Java SE 1.6 RMI implementation running on Linux. 它使用在Linux上运行的Java SE 1.6 RMI实现。 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. 我观察到的问题是,如果客户端使用注册表获得对我的Remote对象的引用,然后突然断开连接(断电,拔掉电缆等),服务器将保持套接字打开。 I would expect the RMI implementation to clean up after the client's lease expires, but that is not happening. 我希望在客户端的租约到期后可以清除RMI实施,但这没有发生。 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. 在服务器上,租约到期时,将调用我的Remote对象的unreferenced()方法,但是套接字在netstat中始终处于“ ESTABLISHED”状态,仍然可见。

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. 由于我们无法强制客户端采取任何特定的行为,因此几天后,我们达到了Linux发行版中针对打开文件描述符的默认限制1024,从而导致服务器无法打开任何新的套接字或文件。 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. 我曾考虑过TCP keepalive,但是由于RMI正在抽象化网络层,因此在建立连接后我无权访问实际的服务器套接字。

Is there any way to force the RMI layer to cleanup sockets tied to client connections with expired leases? 有什么方法可以强制RMI层清理与具有到期租约的客户端连接相关的套接字?

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(). 我使用了一个自定义套接字工厂,然后将createServerSocket()返回的ServerSocket实例包装在一个透明包装中,该包装将通过所有方法,但accept()除外。 In the accpet method, keepalives are enabled before the socket is returned. 在accpet方法中,在返回套接字之前启用了keepalive。

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);

and then just use RMI. 然后只需使用RMI。

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; 如果我没记错的话,诀窍是在系统打开第一个套接字之前设法设置工厂。Java不允许覆盖工厂; Java不允许覆盖工厂。 in worst case, use reflection to overwrite it :))) (kidding; would be a hack) 在最坏的情况下,请使用反射将其覆盖:)))(开玩笑;将是一个hack)

Also, you may need to allow specific operation in SecurityManager. 另外,您可能需要允许在SecurityManager中进行特定操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM