Ich habe einige Probleme mit der Java-Socket-API. Ich versuche, die Anzahl der Spieler anzuzeigen, die derzeit mit meinem Spiel verbunden sind. Es ist leicht festzustellen, wann ein Spieler eine Verbindung hergestellt hat. Es scheint jedoch unnötig schwierig zu sein, festzustellen, wann ein Spieler mithilfe der Socket-API die Verbindung getrennt hat.
Das Anrufen isConnected()
eines Sockets, der aus der Ferne getrennt wurde, scheint immer zurückzukehren true
. Ebenso isClosed()
scheint das Aufrufen eines Sockets, der remote geschlossen wurde, immer zurückzukehren false
. Ich habe gelesen, dass, um tatsächlich festzustellen, ob ein Socket geschlossen wurde oder nicht, Daten in den Ausgabestream geschrieben und eine Ausnahme abgefangen werden muss. Dies scheint ein wirklich unreiner Weg zu sein, um mit dieser Situation umzugehen. Wir müssten nur ständig eine Müllnachricht über das Netzwerk spammen, um jemals zu erfahren, wann ein Socket geschlossen wurde.
Gibt es eine andere Lösung?
quelle
0
statt zurückzukehren-1
.In verschiedenen Messaging-Protokollen ist es allgemein üblich, sich gegenseitig zu schlagen (weiterhin Ping-Pakete zu senden). Das Paket muss nicht sehr groß sein. Mit dem Prüfmechanismus können Sie den nicht verbundenen Client erkennen, noch bevor TCP dies im Allgemeinen herausfindet (das TCP-Zeitlimit ist weitaus höher). Senden Sie eine Prüfung und warten Sie etwa 5 Sekunden auf eine Antwort, wenn Sie keine Antwort für beispielsweise 2-3 sehen Bei nachfolgenden Sonden wird Ihr Player getrennt.
Auch verwandte Frage
quelle
Ich sehe die andere Antwort, die gerade veröffentlicht wurde, aber ich denke, Sie sind interaktiv mit Kunden, die Ihr Spiel spielen, daher kann ich einen anderen Ansatz wählen (während BufferedReader in einigen Fällen definitiv gültig ist).
Wenn Sie möchten ... können Sie die Verantwortung für die Registrierung an den Kunden delegieren. Das heißt, Sie hätten eine Sammlung verbundener Benutzer mit einem Zeitstempel für die letzte von jedem empfangene Nachricht. Wenn ein Client eine Zeitüberschreitung aufweist, würden Sie eine erneute Registrierung des Clients erzwingen. Dies führt jedoch zu dem unten stehenden Zitat und der Idee.
Wenn Ihr Java-Code den Socket nicht geschlossen / getrennt hat, wie würden Sie dann darüber informiert, dass der Remote-Host Ihre Verbindung geschlossen hat? Letztendlich macht Ihr Versuch / Fang ungefähr das Gleiche wie ein Poller, der auf Ereignisse in der IST-Buchse wartet. Folgendes berücksichtigen:
Ich denke, eines der Merkmale der abstrahierten Sprachen ist, dass Sie von den Minutien abstrahiert sind. Denken Sie an das Schlüsselwort using in C # (try / finally) für SqlConnection s oder was auch immer ... es sind nur die Kosten für die Geschäftsabwicklung ... Ich denke, dass try / catch / finally das akzeptierte und notwendige Muster für die Verwendung von Socket ist.
quelle
Ich denke, dies ist die Natur von TCP-Verbindungen. In diesen Standards dauert es ungefähr 6 Minuten, bis die Übertragung unterbrochen ist, bevor wir zu dem Schluss kommen, dass die Verbindung unterbrochen ist! Ich glaube nicht, dass Sie eine genaue Lösung für dieses Problem finden können. Vielleicht ist es besser, einen praktischen Code zu schreiben, um zu erraten, wann der Server annehmen sollte, dass eine Benutzerverbindung geschlossen ist.
quelle
Wie @ user207421 sagt, gibt es aufgrund des TCP / IP-Protokollarchitekturmodells keine Möglichkeit, den aktuellen Status der Verbindung zu ermitteln. Der Server muss Sie also bemerken, bevor Sie die Verbindung schließen, oder Sie überprüfen sie selbst.
Dies ist ein einfaches Beispiel, das zeigt, wie der Socket vom Server geschlossen wird:
quelle
So gehe ich damit um
wenn der result.code == null ist
quelle
readLine()
zweimal anrufen . Sie wissen bereits, dass es imelse
Block null war .Wenn Sie unter Linux in einen Socket schreiben (), den die andere, Ihnen unbekannte Seite geschlossen hat, wird ein SIGPIPE-Signal / eine Ausnahme ausgelöst, wie auch immer Sie es aufrufen möchten. Wenn Sie jedoch nicht vom SIGPIPE erfasst werden möchten, können Sie send () mit dem Flag MSG_NOSIGNAL verwenden. Der send () -Aufruf wird mit -1 zurückgegeben. In diesem Fall können Sie errno überprüfen, um zu erfahren, dass Sie versucht haben, eine defekte Pipe (in diesem Fall einen Socket) mit dem Wert EPIPE zu schreiben, der laut errno.h entspricht 32. Als Reaktion auf das EPIPE können Sie versuchen, den Socket erneut zu öffnen und Ihre Informationen erneut zu senden.
quelle
send()
Aufruf gibt nur dann -1 zurück, wenn die ausgehenden Daten lange genug gepuffert wurden, damit die Sendezeitgeber ablaufen. Aufgrund der Pufferung an beiden Enden und der Asynchronitätsend()
unter der Haube wird dies beim ersten Senden nach dem Trennen mit ziemlicher Sicherheit nicht passieren .