Domanda

La mia applicazione abilitata per RMI sembra perdere i socket. Ho un'applicazione Java che fornisce un servizio su RMI. Sta usando l'implementazione RMI di Java SE 1.6 in esecuzione su Linux. Il problema che sto osservando è che se un client ottiene un riferimento al mio oggetto remoto, usando il Registro di sistema, e quindi la connessione viene interrotta bruscamente (interruzione dell'alimentazione, cavo scollegato, ecc ...), il server mantiene aperto il socket. Mi aspetterei che l'implementazione RMI si ripulisse dopo la scadenza del contratto di locazione del cliente, ma ciò non sta accadendo. Sul server, il metodo unreferenced () del mio oggetto remoto viene chiamato alla scadenza del contratto di locazione, ma il socket rimane visibile in netstat in " ESTABLISHED " stato indefinitamente.

Dal momento che non siamo in grado di forzare i client in alcun comportamento specifico, dopo diversi giorni stiamo raggiungendo il limite predefinito, 1024 nella nostra distribuzione Linux, per i descrittori di file aperti, impedendo al server di aprire nuovi socket o File. Ho pensato ai keepalive TCP, ma poiché RMI sta sottraggendo il livello di rete, non ho accesso al socket del server effettivo dopo aver stabilito la connessione.

Esiste un modo per forzare il livello RMI a pulire i socket collegati alle connessioni client con contratti scaduti?

Aggiornamento: la soluzione che ho usato è simile alla risposta scelta, ma utilizza un approccio diverso. Ho usato una factory socket personalizzata, e quindi ho avvolto l'istanza ServerSocket restituita da createServerSocket () in un wrapper trasparente che ha passato tutti i metodi, ad eccezione di accept (). Nel metodo accpet, keepalive è abilitato prima che venga restituito il 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;
    }
    .
    .
    .
}
È stato utile?

Soluzione

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

Socket.setSocketImplFactory(youFactoryDemandingKeepAlive);

e quindi basta usare RMI.

Il trucco, se ricordo bene, è riuscire a impostare la fabbrica prima che il sistema apra il primo socket - Java non consente di sovrascrivere la fabbrica; nel peggiore dei casi, usa la riflessione per sovrascriverlo :))) (scherzando; sarebbe un trucco)

Inoltre, potrebbe essere necessario consentire operazioni specifiche in SecurityManager.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top