2014-10-04 7 views
11

Ho un'applicazione in tempo reale con client che utilizzano websockets per connettersi con un server Spring Framework, che esegue Spring Boot Tomcat. Voglio che il server rapidamente (entro 5 secondi) rilevi quando un client smette di rispondere a causa di una disconnessione di rete o di altri problemi e chiude il web socket.Come si chiude rapidamente un websocket non responsivo in Java Spring Tomcat?

ho cercato

  1. Impostazione del massimo della sessione timeout di inattività, come descritto nella documentazione come "Configurazione del motore WebSocket" http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html

    @Bean 
    public WebSocketHandler clientHandler() { 
        return new PerConnectionWebSocketHandler(ClientHandler.class); 
    } 
    @Bean 
    public ServletServerContainerFactoryBean createWebSocketContainer() { 
        ServletServerContainerFactoryBean container = 
         new ServletServerContainerFactoryBean(); 
        container.setMaxSessionIdleTimeout(5000); 
        container.setAsyncSendTimeout(5000); 
        return container; 
    } 
    

io non sono sicuro che questo è implementato correttamente perché non vedo il collegamento tra ServletServerContainerFactoryBean e la mia generazione di ClientHandlers.

  1. Invio di messaggi ping dal server ogni 2,5 secondi. Dopo aver disconnesso manualmente il client interrompendo la connessione di rete, il server invia volentieri ping per altri 30+ secondi fino a quando non viene visualizzato un errore di trasporto.

  2. 1 e 2 contemporaneamente

  3. 1 e 2 e l'impostazione server.session-timeout = 5 in application.properties

mia metodologia per testare questo è di:

  1. Collegare un websocket da una client laptop sul server Tomcat
  2. Disattivare la connessione di rete sul laptop utilizzando l'interruttore fisico
  3. Attendere per gli eventi server Tomcat

Come fa un server FrameworkTomcat primavera rilevare rapidamente che un client è stato disconnesso o non risponde per chiudere la websocket?

risposta

1

L'approccio alla fine è stato quello di implementare un protocollo ping-pong a livello di applicazione.

  • Il server invia un messaggio ping con periodo p al client.
  • Il client risponde a ciascun messaggio ping con un messaggio pong.
  • Se il server invia più di n messaggi ping senza ricevere una risposta pong, genera un evento di timeout.
  • Il client può anche generare un evento di timeout se non riceve un messaggio ping nel tempo n*p.

Ci dovrebbe essere un modo molto più semplice di implementare questo utilizzando i timeout nella connessione TCP sottostante.

4

Application Events potrebbe aiutarti.

PS: Annotation driven events

PS2: ho fatto un example project per voi

+0

La mia risposta contiene un esempio di progetto. Non è abbastanza? – Hyperion

+1

È molto utile fornire un progetto di esempio, ma i progetti GitHub svaniscono sempre. Se lo fa, la tua risposta non sarà più utile. Ecco perché ho detto che i post dovrebbero essere autosufficienti. Puoi sempre fornire risorse esterne come riferimento, ma i post di StackOverflow dovrebbero contenere alcuni contenuti. –

+1

È necessario utilizzare STOMP per utilizzare questi eventi? Attualmente sto usando solo una websocket "grezza". – mattm

1

ServletServerContainerFactoryBean semplicemente configura il sottostante JSR-356 WebSocketContainer attraverso la configurazione primavera all'avvio. Se sbirci dentro, vedrai che è banale.

Da quello che posso vedere nel codice Tomcat relativo alla gestione di maxSessionIdleTimeout, il metodo WsWebSocketContainer # backgroundProcess() viene eseguito ogni 10 secondi per impostazione predefinita per vedere se ci sono sessioni scadute.

Sospetto anche che i ping inviati dal server stiano rendendo attiva la sessione, quindi non aiutano per quanto riguarda la configurazione di timeout della sessione inattiva.

Sul motivo per cui Tomcat non si rende conto che il client viene disconnesso prima, non posso davvero dire.Nella mia esperienza se un client chiude una connessione WebSocket o se cancello il browser viene rilevato immediatamente. In ogni caso, questo ha più a che fare con Tomcat e non con Spring.