Primeira vez que implemento Sockets em java, e estou com uma dúvida, nem sei se é possível fazer isto, mas vamos lá.
Faço a comunicação de um client Socket, desenvolvido em java que precisa receber algumas informações de um server Socket, este server não consigo fazer nenhuma alteração, pois é de terceiros.
Consigo efetuar a comunicação e recebo tudo certinho do server, tudo em thread de acordo com uma configuração de arquivo property para cada conexão e caso seja gerado algum problema, o serviço sempre tentará reiniciar, caso o server seja parado por exemplo.
A única situação que restou tratar é que, depois que o serviço foi iniciado com sucesso, tanto server quanto client, se eu tirar o cabo do server por exemplo, para simular algum problema na rede, o client trava completamente, não retorna nenhum tipo de erro, e nem mata a thread em que esta sendo executado, pois se isso acontecesse, a thread seria reiniciada. Quando isto ocorre, somente reiniciando o executável manualmente mesmo para retomar a atividade.
Pesquisando achei algo sobre o KEEP_ALIVE do socket, que em java não é possível ser alterado, somente nas configurações do SO, mas gostaria de verificar se alguém já passou por isso e sabe de uma solução melhor para aplicar.
em primeiro lugar, vc deveria fazer um teste bem simples onde vc tem apenas um socket conectado no server e ai vc interrompe a comunicação ( não precisa tirar o cabo de rede se vc estiver usando um sistema operacional de verdade como Linux + iptables ).
depois vc tem que entender como sockets e o seu sistema operacional funcionam. a opção KEEP ALIVE, por exemplo, pode ser alterada sim no java com um simples socket.setKeepAlive(true); porem isso apenas adiciona uma checagem do sistema operacional que a cada ~ 2 horas ( e isso voce precisa alterar nas configurações do SO se quiser um valor mais adequado) vai verificar se o socket ainda esta de pé ( pois algumas coisas atrapalham a detecção da queda de conexão como load balancers ).
o que acontece quando se perde a conexão é que numa operação read() por exemplo, pode retornar -1 (EOF) ou lançar uma SocketException (“connection reset”). e é ai que o bixo pega.
vc não mencionou nada sobre o protocolo que vc usa entre o servidor e o cliente. se o cliente é que recebe os dados ou ele pede ( diferença entre push e pull ). se o seu cliente só lê e as vezes não tem nada, se vc recebe -1 sempre ( ai cabe vc criar um modo debug onde vc imprime o que vc leu, quantos bytes, etc ) isso pode ser confundido com “não tem nada pra fazer”. se o seu protocolo é orientado a linha ( como o protocolo do Redis por exemplo ) então vc usa um buffer e é mais um cara pra atrapalhar.
minha sugestão é:
explique o protocolo
dentro do seu protocolo, pense em como o cliente detectaria que o socket foi fechado? vc tem algum tipo de heartbeat?
veja se vc não tem espaço pra forçar um reconnect em cada x minutos sem dados.
um erro fundamental quando vc implementa o seu cliente ou server é não cuidar do ciclo de vida dos seus sockets. por isso que é preferivel vc usar um protocolo como HTTP pois:
a. vc pode conectar, fazer o request e desconectar.
b. a maioria das implementações sabe lidar muito bem com o ciclo devida dos sockets, incluindo deixar a conexão aberta e enviar um stream de dados caso necessario.
c. vc tem os codigos de retorno e os cabeçalhos que ajudam demais
d. é facil de escalar pois o protocolo é stateless
vc infelizmente tem algo especializado. mas sera que um Vert.x não vai ajudar a conectar, por exemplo, de uma forma melhor não?
vc esta usando threads pois o read/write são operações bloqueantes. provavelmente seu client fica lendo o socket esperando coisas e entra em loop pois o socket parece ativo. vc tem a opção de fazer um debug remoto do seu client pra ver o que entrou em loop.
Eu já faço esse teste bem simples, sem thread com o socket, se paro o serviço do server, blz, o client gera uma exception que eu consigo tratar e reiniciar sozinho, mas também preciso tratar a situação de um problema na rede, no caso, tirar o cabo com o serviço rodando.
O ambiente em que desenvolvo é windows, não tem jeito.
Sim, com o socket.setKeepAlive(true), seria necessário alterar a configuração do SO, o que não fica viável.
O Protocolo, acredito que por utilizar o Socket, seria TCPIP, não sei se dá gerar algum outro tipo com esta estrutura.
Explicando um pouco mais sobre a estrutura montada, o socket client “escuta” uma porta do socket server, e assim o server mandar algo, o client captura, então, utilizo o while ((str = br.readLine()) != null) {}.
Testei a respeito do read(); já tinha realizado um teste, para tentar tratar o retorno de -1, mas ao desconectar o cabo do server ele também trava, na realidade, tudo que esta dentro do while citado acima, acredito que devido ao retorno do objeto socket.getInputStream().
Ainda não sei se isso que quero tratar é possível com sockets.
Esqueci de postar aqui, mas a resolução é bem simples, o próprio objeto do socket depois de instanciado tem um método de setar o timeout, que caso passe este tempo sem que o readline() não retorne nada ele dispara um SocketTimeoutException, ai é só tratar e reiniciar o processo pra tentar reconectar.
Socket socket = new Socket(ip, porta); socket.setSoTimeout(30000);