A seguito di una recente domanda , mi chiedo perché sia impossibile in Java, senza tentare di leggere / scrivere su un socket TCP, rilevare che il socket è stato chiuso con grazia dal peer? Questo sembra essere il caso indipendentemente dal fatto che si utilizzi il pre-NIO Socket
o il NIO SocketChannel
.
Quando un peer chiude con grazia una connessione TCP, gli stack TCP su entrambi i lati della connessione ne sono a conoscenza. Il lato server (quello che avvia l'arresto) finisce nello stato FIN_WAIT2
, mentre il lato client (quello che non risponde esplicitamente allo spegnimento) finisce nello stato CLOSE_WAIT
. Perché non c'è un metodo Socket
o SocketChannel
che può interrogare lo stack TCP per vedere se la connessione TCP sottostante è stata terminata? È che lo stack TCP non fornisce tali informazioni sullo stato? O è una decisione progettuale per evitare una chiamata costosa nel kernel?
Con l'aiuto degli utenti che hanno già pubblicato alcune risposte a questa domanda, penso di vedere da dove potrebbe provenire il problema. Il lato che non chiude esplicitamente la connessione finisce nello stato TCP, CLOSE_WAIT
il che significa che la connessione è in fase di chiusura e attende che il lato esegua la propria CLOSE
operazione. Suppongo sia abbastanza giusto che isConnected
ritorni true
e isClosed
ritorni false
, ma perché non c'è qualcosa di simile isClosing
?
Di seguito sono riportate le classi di test che utilizzano socket pre-NIO. Ma risultati identici si ottengono usando NIO.
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer {
public static void main(String[] args) throws Exception {
final ServerSocket ss = new ServerSocket(12345);
final Socket cs = ss.accept();
System.out.println("Accepted connection");
Thread.sleep(5000);
cs.close();
System.out.println("Closed connection");
ss.close();
Thread.sleep(100000);
}
}
import java.net.Socket;
public class MyClient {
public static void main(String[] args) throws Exception {
final Socket s = new Socket("localhost", 12345);
for (int i = 0; i < 10; i++) {
System.out.println("connected: " + s.isConnected() +
", closed: " + s.isClosed());
Thread.sleep(1000);
}
Thread.sleep(100000);
}
}
Quando il client di prova si connette al server di prova, l'output rimane invariato anche dopo che il server ha avviato l'arresto della connessione:
connected: true, closed: false
connected: true, closed: false
...