Pour faire suite à une question récente , je me demande pourquoi il est impossible en Java, sans tenter de lire / écrire sur une socket TCP, de détecter que la socket a été gracieusement fermée par le pair? Cela semble être le cas, que l'on utilise le pré-NIO Socket
ou le NIO SocketChannel
.
Lorsqu'un homologue ferme en douceur une connexion TCP, les piles TCP des deux côtés de la connexion sont au courant du fait. Le côté serveur (celui qui initie l'arrêt) se retrouve dans l'état FIN_WAIT2
, tandis que le côté client (celui qui ne répond pas explicitement à l'arrêt) finit dans l'état CLOSE_WAIT
. Pourquoi n'y a-t-il pas de méthode dans Socket
ou SocketChannel
qui puisse interroger la pile TCP pour voir si la connexion TCP sous-jacente a été interrompue? Est-ce que la pile TCP ne fournit pas de telles informations d'état? Ou est-ce une décision de conception pour éviter un appel coûteux dans le noyau?
Avec l'aide des utilisateurs qui ont déjà publié des réponses à cette question, je pense voir d'où vient le problème. Le côté qui ne ferme pas explicitement la connexion se retrouve dans l'état TCP, CLOSE_WAIT
ce qui signifie que la connexion est en train de s'arrêter et attend que le côté émette sa propre CLOSE
opération. Je suppose que c'est assez juste que les isConnected
retours true
et les isClosed
retours false
, mais pourquoi n'y a-t-il pas quelque chose comme ça isClosing
?
Vous trouverez ci-dessous les classes de test qui utilisent des sockets pré-NIO. Mais des résultats identiques sont obtenus en utilisant 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);
}
}
Lorsque le client de test se connecte au serveur de test, la sortie reste inchangée même après que le serveur a initié l'arrêt de la connexion:
connected: true, closed: false
connected: true, closed: false
...