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 Socketo 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 Socketo SocketChannelche 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_WAITil che significa che la connessione è in fase di chiusura e attende che il lato esegua la propria CLOSEoperazione. Suppongo sia abbastanza giusto che isConnectedritorni truee isClosedritorni 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
...