it-swarm.com.de

Java-Socket-API: Wie kann ich feststellen, ob eine Verbindung geschlossen wurde?

Ich habe Probleme mit der Java-Socket-API. Ich versuche, die Anzahl der Spieler anzuzeigen, die aktuell mit meinem Spiel verbunden sind. Es ist leicht festzustellen, wann ein Spieler eine Verbindung hergestellt hat. Es scheint jedoch unnötig schwierig zu bestimmen, wann ein Spieler die Verbindung mit der Socket-API getrennt hat.

Das Aufrufen von isConnected() für einen Remote-Socket, der entfernt wurde, scheint immer true zurückzugeben. In ähnlicher Weise scheint der Aufruf von isClosed() für einen Remote-Socket immer false zurückzugeben. Ich habe gelesen, um festzustellen, ob ein Socket geschlossen wurde oder nicht, Daten in den Ausgabestrom geschrieben werden müssen und eine Ausnahme abgefangen werden muss. Dies scheint ein wirklich unreiner Weg zu sein, um mit dieser Situation umzugehen. Wir müssten einfach ständig eine Müllnachricht über das Netzwerk spammen, um zu wissen, wann ein Socket geschlossen wurde.

Gibt es eine andere Lösung?

65
Dan Brouwer

Es gibt keine TCP API, die Ihnen den aktuellen Status der Verbindung anzeigt. isConnected() und isClosed() teilen Ihnen den aktuellen Zustand mit Ihrer Steckdose. Nicht dasselbe.

  1. isConnected() sagt Ihnen, ob Sie verbunden haben diese Buchse. Sie haben, also gibt es wahr zurück.

  2. isClosed() gibt an, ob Sie geschlossen haben dieser Socket Bis dahin wird false zurückgegeben.

  3. Wenn der Peer die Verbindung ordnungsgemäß geschlossen hat

    • read() gibt -1 zurück
    • readLine() gibt null zurück
    • readXXX() wirft EOFException für alle anderen XXX.

    • Ein Schreibvorgang löst ein IOException aus: 'Verbindung durch Peer zurückgesetzt', was eventuell zu Verzögerungen beim Puffern führt.

  4. Wenn die Verbindung aus einem anderen Grund getrennt wurde, gibt ein Schreibvorgang wie oben ein IOException aus, und ein Lesevorgang kann dasselbe tun.

  5. Wenn der Peer noch verbunden ist, aber die Verbindung nicht verwendet, kann ein Lesezeitlimit verwendet werden.

  6. Im Gegensatz zu dem, was Sie an anderer Stelle gelesen haben, sagt Ihnen ClosedChannelException dies nicht. [Weder tut SocketException: socket closed.] Es sagt Ihnen nur, dass Sie den Kanal geschlossen und dann weiter verwendet hat. Mit anderen Worten, ein Programmierfehler von Ihrer Seite. Es zeigt keine geschlossene Verbindung.

  7. Als Ergebnis einiger Experimente mit Java 7 unter Windows XP scheint es auch so zu sein, dass wenn:

    • sie wählen auf OP_READ
    • select() gibt einen Wert größer als Null zurück
    • das zugehörige SelectionKey ist bereits ungültig (key.isValid() == false)

    dies bedeutet, dass der Peer die Verbindung zurückgesetzt hat. Dies gilt jedoch möglicherweise nur für die JRE-Version oder die JRE-Plattform.

157
user207421

In verschiedenen Messaging-Protokollen ist es allgemein üblich, sich gegenseitig zu schlagen (ping-Pakete weiter zu senden). Das Paket muss nicht sehr groß sein. Der Prüfmechanismus ermöglicht es Ihnen, den getrennten Client zu erkennen, noch bevor TCP das generell herausfindet (TCP-Zeitüberschreitung ist viel höher). Senden Sie eine Prüfung und warten Sie etwa 5 Sekunden auf eine Antwort, wenn Sie keine Antwort sehen sagen Sie 2-3 aufeinander folgende Sonden, Ihr Player ist nicht verbunden.

Auch verwandte Frage

6
Kalpak Gadre

Ich sehe die andere Antwort gerade gepostet, aber ich denke, Sie sind interaktiv mit Kunden, die Ihr Spiel spielen, daher kann ich einen anderen Ansatz einlegen (obwohl BufferedReader in manchen Fällen durchaus gültig ist).

Wenn Sie ... wollten 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 jeweils letzte Nachricht. Wenn ein Client das Zeitlimit überschreitet, würden Sie eine erneute Registrierung des Clients erzwingen. Dies führt jedoch zu dem unten angegebenen Angebot und der folgenden Idee.

Ich habe das gelesen, um festzustellen, ob ein Socket .__ hat oder nicht. Geschlossene Daten müssen in den Ausgabestrom geschrieben werden und eine Ausnahme muss gefangen werden Dies scheint eine wirklich unsaubere Art und Weise zu sein. Situation.

Wenn Ihr Java-Code den Socket nicht geschlossen/getrennt hat, wie würden Sie sonst benachrichtigt, dass der Remote-Host Ihre Verbindung getrennt hat? Letztendlich macht Ihr Try/Catch ungefähr das gleiche wie ein Poller, der Ereignisse auf dem ACTUAL-Socket überwacht. Folgendes berücksichtigen:

  • ihr lokales System könnte Ihren Socket schließen, ohne Sie darüber zu informieren. Dies ist nur die Implementierung von Socket (d. h. es fragt die Hardware/den Treiber/die Firmware/was auch immer nach Statusänderung ab).
  • neuer Socket (Proxy p) ... es gibt mehrere Parteien (wirklich 6 Endpunkte), die die Verbindung für Sie schließen könnten ...

Ich denke, eines der Merkmale der abstrahierten Sprachen ist, dass Sie von den Minuzien abstrahiert werden. Denken Sie an das Schlüsselwort using in C # (try/finally) für SqlConnection oder was auch immer ... es sind nur die Kosten für das Geschäft ... Ich denke, dass try/catch/endlich das akzeptierte und notwendige Muster für Socket ist.

2
Scottley

Ich denke, dies ist die Natur von TCP-Verbindungen. In diesen Standards dauert es etwa sechs Minuten, bis die Übertragung still ist, bevor wir zu dem Schluss kommen, dass die Verbindung nicht mehr besteht!. Vielleicht ist es besser, einen praktischen Code zu schreiben, um zu erraten, wann der Server eine Benutzerverbindung unterbrechen sollte.

1

So gehe ich damit um

 while(true) {
        if((receiveMessage = receiveRead.readLine()) != null ) {  

        System.out.println("first message same :"+receiveMessage);
        System.out.println(receiveMessage);      

        }
        else if(receiveRead.readLine()==null)
        {

        System.out.println("Client has disconected: "+sock.isClosed()); 
        System.exit(1);
         }    } 

wenn der result.code == null ist

0
Petar Ceho

Wie @ user207421 sagt, gibt es aufgrund des TCP/IP-Protokollarchitekturmodells keine Möglichkeit, den aktuellen Status der Verbindung zu erfahren. Der Server muss Sie also vor dem Schließen der Verbindung bemerken, oder Sie prüfen sie selbst. 
Dies ist ein einfaches Beispiel, das zeigt, wie der Socket vom Server geschlossen wird:

sockAdr = new InetSocketAddress(SERVER_HOSTNAME, SERVER_PORT);
socket = new Socket();
timeout = 5000;
socket.connect(sockAdr, timeout);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream());
while ((data = reader.readLine())!=null) 
      log.e(TAG, "received -> " + data);
log.e(TAG, "Socket closed !");
0
ucMedia