Pregunta

Mi aplicación habilitada para RMI parece estar perdiendo sockets. Tengo una aplicación Java que proporciona un servicio a través de RMI. Está utilizando la implementación de Java SE 1.6 RMI que se ejecuta en Linux. El problema que estoy observando es que si un cliente obtiene una referencia a mi objeto Remoto, usando el Registro, y luego la conexión se corta abruptamente (pérdida de energía, cable desconectado, etc.), el servidor mantiene el zócalo abierto. Espero que la implementación de RMI se limpie después de que caduque el contrato del cliente, pero eso no está sucediendo. En el servidor, se llama al método no referenciado () de mi objeto Remoto cuando expira la concesión, pero el socket permanece visible en netstat en la sección ESTABLISHED " estado indefinidamente.

Ya que no podemos forzar a los clientes a ningún comportamiento específico, después de varios días estamos alcanzando el límite predeterminado, 1024 en nuestra distribución de Linux, para los descriptores de archivos abiertos, lo que hace que el servidor no pueda abrir ningún socket nuevo o archivos. Pensé en TCP keepalives, pero como RMI está abstrayendo la capa de red, no tengo acceso al socket del servidor real después de que se haya establecido la conexión.

¿Hay alguna forma de obligar a la capa RMI a limpiar los sockets vinculados a las conexiones de los clientes con contratos vencidos?

Actualización: La solución que utilicé es similar a la respuesta elegida, pero utiliza un enfoque diferente. Utilicé una fábrica de zócalos personalizados, y luego envolví la instancia de ServerSocket devuelta por createServerSocket () en un envoltorio transparente que pasaba todos los métodos, excepto accept (). En el método accpet, los keepalives están habilitados antes de que se devuelva el socket.

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;
    }
    .
    .
    .
}
¿Fue útil?

Solución

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

Socket.setSocketImplFactory(youFactoryDemandingKeepAlive);

y luego solo usa RMI.

El truco, si recuerdo bien, es lograr establecer la fábrica antes de que el sistema abra el primer zócalo: Java no permite sobrescribir la fábrica; en el peor de los casos, use la reflexión para sobrescribirlo :))) (es broma, sería un hack)

Además, es posible que deba permitir una operación específica en SecurityManager.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top