Seguindo uma pergunta recente , eu me pergunto por que é impossível em Java, sem tentar ler / gravar em um soquete TCP, detectar que o soquete foi normalmente fechado pelo par? Este parece ser o caso, independentemente de se usar o pré-NIO Socket
ou o NIO SocketChannel
.
Quando um par fecha normalmente uma conexão TCP, as pilhas TCP em ambos os lados da conexão sabem sobre o fato. O lado do servidor (aquele que inicia o desligamento) termina no estado FIN_WAIT2
, enquanto o lado do cliente (aquele que não responde explicitamente ao desligamento) termina no estado CLOSE_WAIT
. Por que não existe um método em Socket
ou SocketChannel
que possa consultar a pilha TCP para ver se a conexão TCP subjacente foi encerrada? É que a pilha TCP não fornece essas informações de status? Ou é uma decisão de design para evitar uma chamada dispendiosa para o kernel?
Com a ajuda dos usuários que já postaram algumas respostas para essa pergunta, acho que vejo de onde o problema pode estar vindo. O lado que não fecha explicitamente a conexão termina no estado TCP, CLOSE_WAIT
o que significa que a conexão está em processo de encerramento e espera que o lado execute sua própria CLOSE
operação. Suponho que seja justo que isConnected
volte true
e isClosed
volte false
, mas por que não existe algo assim isClosing
?
Abaixo estão as classes de teste que usam soquetes pré-NIO. Mas resultados idênticos são obtidos 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 o cliente de teste se conecta ao servidor de teste, a saída permanece inalterada, mesmo após o servidor iniciar o desligamento da conexão:
connected: true, closed: false
connected: true, closed: false
...
Socket.close
não é um encerramento elegante.