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 Socketou 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 Socketou SocketChannelque 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_WAITo que significa que a conexão está em processo de encerramento e espera que o lado execute sua própria CLOSEoperação. Suponho que seja justo que isConnectedvolte truee isClosedvolte 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.closenão é um encerramento elegante.