Ho un codice Java che rende una connessione socket a lungo termine a un dispositivo domotico per monitorarlo per attività/eventi. Il problema è che se il dispositivo viene riavviato o viene riacceso, il codice Java dovrebbe riconnettersi automaticamente il prima possibile. Qualche idea su come rilevare una connessione interrotta sul lato Java, preferibilmente senza il polling periodico del dispositivo?Ricollegare una connessione socket Java su disconnessione
risposta
Se il dispositivo si riavvia senza chiudere correttamente la presa, non conosco nulla che permetta di rilevarlo. Il tuo server non sarà in grado di rilevare che il socket è andato via, in questo caso, a meno che il dispositivo non ritorni su o finché lo stack TCP/IP sul server non si arresta e dichiara che la connessione è morta. Ad un certo punto riceverai un IOException.
Devi catturare quell'eccezione e quindi riconnetterti quando si verifica.
Sei davvero in balia del comportamento di TCP/IP qui. Quando una estremità di una connessione scompare semplicemente (nessun pacchetto FIN
), l'altra estremità può attendere un intervallo di tempo arbitrario (a seconda di molti fattori) prima di decidere che la connessione è morta.
Se si desidera rilevare questo problema in precedenza, è possibile garantire che il dispositivo risponda entro un determinato periodo di tempo, quindi impostare un timeout sul socket. Se lo fai, riceverai un SocketTimeoutException
se il dispositivo non risponde e potrai quindi chiudere il socket e provare a riaprire il socket. L'ho usato con successo.
Se il software è solo in attesa di dati dal dispositivo di automazione domestica, l'unico modo per rilevare che il dispositivo è andato è abilitare l'opzione SO_KEEPALIVE nel socket aperto per comunicare con il dispositivo.
Per fare ciò basta chiamare il metodo setKeepAlive (true) sul socket e questo renderà l'implementazione del socket sottostante abilitare l'opzione SO_KEEP_ALIVE.
In questo modo l'implementazione sottostante scambierà periodicamente alcuni dati con l'endpoint remoto e se il dispositivo muore mentre si è in attesa di dati, verrà generata un'eccezione.
L'unico problema è che il time-out keep-alive dipende dal sistema operativo e talvolta non può essere modificato.
Se sono necessari timeout più brevi, non c'è altro modo che implementare una sonda periodica sul dispositivo.
Ho risolto esattamente lo stesso problema.
Se si desidera rilevare questo problema in precedenza, è possibile garantire che il dispositivo risponda entro un determinato periodo di tempo, quindi impostare un timeout sul socket. Se lo fai, otterrai una SocketTimeoutException se il dispositivo non risponde e potrai quindi chiudere il socket e provare a riaprire il socket. L'ho usato con successo.
Citato dall'alto:
ottengo a chiudere la presa quindi si tenta di riaprirlo, che viene eseguito quel codice soddisfacente. L'unico problema è che, una volta chiusa una presa, non è possibile riaprirla con lo , ma ho l'eccezione che il socket è chiuso. Questo si verifica ogni volta. Come posso chiudere un socket, quindi riaprirlo senza ottenendo questa eccezione?