Estou tendo alguns problemas com a API de soquete Java. Estou tentando exibir o número de jogadores atualmente conectados ao meu jogo. É fácil determinar quando um jogador está conectado. No entanto, parece desnecessariamente difícil determinar quando um jogador se desconectou usando a API de soquete.
Chamar isConnected()
um soquete que foi desconectado remotamente sempre parece retornar true
. Da mesma forma, chamar isClosed()
em um soquete que foi fechado remotamente sempre parece retornar false
. Eu li que para realmente determinar se um soquete foi fechado ou não, os dados devem ser gravados no fluxo de saída e uma exceção deve ser detectada. Esta parece ser uma maneira muito suja de lidar com essa situação. Teríamos apenas que enviar spam constantemente uma mensagem de lixo pela rede para saber quando um soquete foi fechado.
existe alguma outra solução?
fonte
0
invés de-1
.É uma prática geral em vários protocolos de mensagens manter a pulsação uns dos outros (continuar enviando pacotes de ping); o pacote não precisa ser muito grande. O mecanismo de sondagem permitirá que você detecte o cliente desconectado antes mesmo que o TCP descubra em geral (o tempo limite do TCP é muito maior) Envie uma sondagem e espere, digamos, 5 segundos por uma resposta, se você não vir a resposta por digamos 2-3 sondas subsequentes, o seu aparelho é desconectado.
Além disso, questão relacionada
fonte
Vejo a outra resposta que acabei de postar, mas acho que você é interativo com os clientes que jogam seu jogo, então posso propor outra abordagem (enquanto BufferedReader é definitivamente válido em alguns casos).
Se você quiser ... você pode delegar a responsabilidade do "registro" ao cliente. Ou seja, você teria uma coleção de usuários conectados com um carimbo de data / hora na última mensagem recebida de cada um ... se um cliente expirar, você forçaria um novo registro do cliente, mas isso leva à cotação e ideia abaixo.
Se seu código Java não fechou / desconectou o Socket, de que outra forma você seria notificado de que o host remoto fechou sua conexão? Em última análise, seu try / catch está fazendo quase a mesma coisa que um poller que escuta eventos no soquete ACTUAL estaria fazendo. Considere o seguinte:
Acho que uma das características das linguagens abstratas é que você é abstraído das minúcias. Pense na palavra-chave using em C # (try / finally) para SqlConnection s ou qualquer outra coisa ... é apenas o custo de fazer negócios ... Acho que try / catch / finally é o padrão aceito e necessário para uso de Socket.
fonte
Acho que essa é a natureza das conexões tcp, nos padrões que leva cerca de 6 minutos de silêncio na transmissão antes de concluirmos que nossa conexão acabou! Portanto, não acho que você possa encontrar uma solução exata para este problema. Talvez a melhor maneira seja escrever algum código útil para adivinhar quando o servidor deve supor que a conexão do usuário foi fechada.
fonte
Como @ user207421 diz que não há como saber o estado atual da conexão devido ao modelo de arquitetura de protocolo TCP / IP. Portanto, o servidor deve notá-lo antes de fechar a conexão ou você verificar por si mesmo.
Este é um exemplo simples que mostra como saber se o soquete foi fechado pelo servidor:
fonte
Eu enfrentei um problema semelhante. No meu caso, o cliente deve enviar dados periodicamente. Espero que você tenha o mesmo requisito. Então eu defino SO_TIMEOUT
socket.setSoTimeout(1000 * 60 * 5);
que é lançadojava.net.SocketTimeoutException
quando o tempo especificado expira. Assim, posso detectar facilmente o cliente morto.fonte
É assim que eu lido com isso
se o result.code == null
fonte
readLine()
duas vezes. Você já sabe que era nulo noelse
bloco.No Linux, ao escrever () em um socket que o outro lado, desconhecido para você, fechou irá provocar um sinal / exceção SIGPIPE como você quiser chamá-lo. No entanto, se você não quiser ser pego pelo SIGPIPE, pode usar send () com o sinalizador MSG_NOSIGNAL. A chamada send () retornará com -1 e neste caso você pode verificar errno que lhe dirá que você tentou escrever um pipe quebrado (neste caso um socket) com o valor EPIPE que de acordo com errno.h é equivalente a 32. Como reação ao EPIPE, você pode voltar e tentar reabrir o soquete e tentar enviar suas informações novamente.
fonte
send()
chamada retornará -1 apenas se os dados de saída forem armazenados em buffer por tempo suficiente para que os temporizadores de envio expirem. É quase certo que isso não acontecerá no primeiro envio após a desconexão, devido ao armazenamento em buffer em ambas as extremidades e à natureza assíncrona dossend()
bastidores.