Je rencontre des problèmes avec l'API de socket Java. J'essaye d'afficher le nombre de joueurs actuellement connectés à mon jeu. Il est facile de déterminer quand un joueur s'est connecté. Cependant, il semble inutilement difficile de déterminer quand un joueur s'est déconnecté à l'aide de l'API socket.
L'appel isConnected()
sur une socket qui a été déconnectée à distance semble toujours revenir true
. De même, appeler isClosed()
une socket qui a été fermée à distance semble toujours revenir false
. J'ai lu que pour déterminer réellement si une socket a été fermée ou non, les données doivent être écrites dans le flux de sortie et une exception doit être interceptée. Cela semble être une manière vraiment impure de gérer cette situation. Nous aurions juste constamment à spammer un message indésirable sur le réseau pour savoir quand un socket s'est fermé.
N 'y a-t-il pas une autre solution?
la source
0
au lieu de-1
.Il est de pratique générale dans divers protocoles de messagerie de continuer à battre les uns les autres (continuer à envoyer des paquets ping), le paquet n'a pas besoin d'être très volumineux. Le mécanisme de sondage vous permettra de détecter le client déconnecté avant même que TCP ne le comprenne en général (le délai d'expiration TCP est beaucoup plus élevé) Envoyez une sonde et attendez par exemple 5 secondes pour une réponse, si vous ne voyez pas la réponse pour disons 2-3 sondes suivantes, votre lecteur est déconnecté.
Aussi, question connexe
la source
Je vois l'autre réponse qui vient d'être publiée, mais je pense que vous êtes interactif avec les clients qui jouent à votre jeu, donc je peux proposer une autre approche (alors que BufferedReader est certainement valable dans certains cas).
Si vous le souhaitez ... vous pouvez déléguer la responsabilité de «l'enregistrement» au client. C'est-à-dire que vous auriez une collection d'utilisateurs connectés avec un horodatage sur le dernier message reçu de chacun ... si un client expire, vous forceriez une réinscription du client, mais cela conduit au devis et à l'idée ci-dessous.
Si votre code Java n'a pas fermé / déconnecté le socket, comment seriez-vous averti que l'hôte distant a fermé votre connexion? En fin de compte, votre try / catch fait à peu près la même chose qu'un poller écoutant les événements sur le socket ACTUAL. Considérer ce qui suit:
Je pense que l'une des caractéristiques des langages abstraits est que vous êtes abstraits de la minutie. Pensez au mot clé using en C # (try / finally) pour SqlConnection ou autre ... c'est juste le coût de faire des affaires ... Je pense que try / catch /
la source
Je pense que c'est la nature des connexions TCP, en ce sens qu'il faut environ 6 minutes de silence en transmission avant de conclure que la connexion est terminée! Je ne pense donc pas que vous puissiez trouver une solution exacte à ce problème. La meilleure façon est peut-être d'écrire du code pratique pour deviner quand le serveur doit supposer qu'une connexion utilisateur est fermée.
la source
Comme le dit @ user207421, il n'y a aucun moyen de connaître l'état actuel de la connexion en raison du modèle d'architecture de protocole TCP / IP. Le serveur doit donc vous remarquer avant de fermer la connexion ou vous la vérifiez vous-même.
Voici un exemple simple qui montre comment savoir que le socket est fermé par le serveur:
la source
J'ai fait face à un problème similaire. Dans mon cas, le client doit envoyer des données périodiquement. J'espère que vous avez la même exigence. Ensuite, j'ai défini SO_TIMEOUT
socket.setSoTimeout(1000 * 60 * 5);
qui est lancéjava.net.SocketTimeoutException
lorsque le temps spécifié est expiré. Ensuite, je peux détecter facilement un client mort.la source
C'est comme ça que je gère ça
si le result.code == null
la source
readLine()
deux fois. Vous savez déjà qu'il était nul dans leelse
bloc.Sous Linux, lors de l'écriture () dans un socket que l'autre côté, inconnu de vous, fermé provoquera un signal / exception SIGPIPE comme vous voulez l'appeler. Cependant, si vous ne voulez pas être attrapé par le SIGPIPE, vous pouvez utiliser send () avec le drapeau MSG_NOSIGNAL. L'appel send () retournera avec -1 et dans ce cas vous pouvez vérifier errno qui vous dira que vous avez essayé d'écrire un tube cassé (dans ce cas une socket) avec la valeur EPIPE qui selon errno.h équivaut à 32. En réaction à l'EPIPE, vous pouvez revenir en arrière et essayer de rouvrir le socket et essayer de renvoyer vos informations.
la source
send()
appel renverra -1 uniquement si les données sortantes ont été mises en mémoire tampon suffisamment longtemps pour que les temporisations d'envoi expirent. Cela ne se produira presque certainement pas lors du premier envoi après la déconnexion, en raison de la mise en mémoire tampon aux deux extrémités et de la nature asynchrone desend()
sous le capot.