Java, Socket: disconnects erkennen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Java, Socket: disconnects erkennen

    Hallo
    Ich suche schon etwas länger im Netz nach der Lösung, zu erkennen, ob ein Socket disconnected ist.
    Die Lösung war fast überall: über input oder output erkennen. Diese Methode funktioniert so ganz gut, nur gibt's dann an anderen Stellen Probleme.
    Hinweis: ich benutze Threads

    Wenn ich es über input mache:

    Quellcode

    1. InputStream is = sock.getInputStream();
    2. if(is.available==0
    3. && is.read()<0)
    4. //Jetzt ist sock disconnected

    Passiert es, dass manchmal dann aber doch der Stream ausgelesen wird. (Hab mir den empfangenden Buffer vor dem benutzen des Codes und danach angeschaut und mit ihm passiert es, dass das erste Byte vom Buffer weg ist)

    Über output, also dass ich dem socket etwas zusende und schaue ob es eine IOException gibt funktioniert zwar, auch gut, aber es ist nicht so toll, dass der Client "zugespamt" wird.

    Würde das nur über output gehen oder habe ich bei input irgendetwas übersehen?
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe
  • InputStream.read() liest immer ein Byte aus dem Stream, wenn man am Ende vom Stream ist (z.B. wenn die Verbindung zu ist), dann kommt -1 zurück. Damit überspringst du aber immer das erste Byte (weil du ja eins liest). In bestimmten Fällen kommt auch eine IOException zurück, möglicherweiße auch dann, wenn die Verbindung geschlossen wurde.

    Du kannst int InputStream.read(byte[] b) benutzen und die Daten in einen Buffer lesen, dann überspringst du nicht das erste Byte. Beachte aber, dass auf Grund der Stream Natur die Daten nicht in Paketen getrennt an kommt (wenn man also einen Buffer von 200 Bytes erstellt, kann es sein, dass man 3 Pakete auf einmal liest und die Hälfte von einem vierten).

    Schau dir mal DataInputStream an.
    wupto.net/ Nicht meine Seite!
    We love Koalas.

    GM-D-Spam-o-Meter: 32%
  • henrik1235 schrieb:

    Du kannst int InputStream.read(byte[] b) benutzen und die Daten in einen Buffer lesen, dann überspringst du nicht das erste Byte. Beachte aber, dass auf Grund der Stream Natur die Daten nicht in Paketen getrennt an kommt (wenn man also einen Buffer von 200 Bytes erstellt, kann es sein, dass man 3 Pakete auf einmal liest und die Hälfte von einem vierten).

    Schau dir mal DataInputStream an.

    Das löse ich auch mithilfe von DataInputStream (und größtenteils von @'LEWA''s Klasse StreamConverter)

    Soweit ich das testen konnte, gibt es leider keine IOException, wodurch ich das dann damit nicht prüfen kann.
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe
  • Hallo :)
    Ich konnte immer noch keine Lösung finden und mir ist aufgefallen, dass ich bei dem ständigen "Spam" andere Nachrichten, die versendet werden sollen untergehen.
    Wüsste noch einer eine gute Lösung?
    PS:Danke für die Info @henrik1235
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe
  • Ein Sockettimeout kann jederzeit auftauchen, egal an welcher stelle das Programm gerade executiert.
    In java kannst du du mit einem try/catch block einfach auf eine Sockettimeoutexception prüfen (welche und (falls diese auftauchen sollte) die jeweiligen maßnahmen treffen.

    Quellcode

    1. public void run() {
    2. try {
    3. while(alive){//Start a do while loop while alive is true
    4. checkForMessages();
    5. //}
    6. }
    7. }catch (SocketTimeoutException ex){//If we get a Socket timeout display it and free the player's instance
    8. //server.consolePrintln("Disconnected player"+player.getID()+" due to TimeOut.");
    9. //ex.printStackTrace();
    10. } catch (IOException e) {
    11. //server.consolePrintln("Disconnected player"+player.getID()+" due to IO Error.");
    12. //ex.printStackTrace();
    13. }finally{
    14. alive = false;
    15. player.closePlayer();
    16. }
    Alles anzeigen


    Wenn ein disconnect auftritt, wird die SocketTimeoutException geworfen und demnach der ganze Thread beendet.
  • Danke Lewa, bis jetzt hat das aber nicht funktioniert.

    Meine Funktion zum empfangen von Nachrichten sieht ungefähr so aus:(bin am Handy)

    Quellcode

    1. InputStream is = sock.getInputStream();
    2. while (is.available<0){}
    3. return new DataInputStream(is);

    Bis jetzt ist, soweit ich weiß, noch keine Exception aufgetreten.

    Im ersten Post habe ich auh mein Code geschrieben, den ich in einem Thread, der für disconnects zuständig war über eine while und for(für alle sockets) Schleife geprüft.
    Dort hat das aber, wie Henrik erklärt hat, nicht gewünscht funktioniert.

    Edit:

    henrik1235 schrieb:

    Du kannst int InputStream.read(byte[] b) benutzen und die Daten in einen Buffer lesen, dann überspringst du nicht das erste Byte

    Das überspringt bei mir schon den ersten Byte:

    Java-Quellcode

    1. InputStream is = sock.getInputStream();
    2. byte[] test = new byte[1];
    3. if(is.available()==0){
    4. is.read(test,0,1);
    5. if(test[0]==0)
    6. closeSocket(sock);
    7. }

    funktioniert sonst aber genauso gut
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Husi012 ()

  • Verwende einen DataInputStream anstelle eines normalen Inputstreams.

    Quellcode

    1. DataInputStream input = new DataInputStream(socket.getInputStream());//Get the Data input stream


    Du kannst dann den inhalt der an den Server gesendet wird ganz einfach auslesen:

    Quellcode

    1. //Thread
    2. @Override
    3. public void run() {
    4. try {
    5. while(alive){//Start a do while loop while alive is true
    6. checkForMessages();
    7. }
    8. }catch (SocketTimeoutException ex){//If we get a Socket timeout display it and free the player's instance
    9. //server.consolePrintln("Disconnected player"+player.getID()+" due to TimeOut.");
    10. } catch (IOException e) {
    11. //server.consolePrintln("Disconnected player"+player.getID()+" due to IO Error.");
    12. }finally{
    13. alive = false;
    14. player.closePlayer();
    15. }
    16. }
    17. private void checkForMessages() throws IOException {
    18. int c1=StreamConverter.buffer_read_u8(input);
    19. int c2=StreamConverter.buffer_read_u8(input);
    20. int c3=StreamConverter.buffer_read_u8(input);
    21. int c4=StreamConverter.buffer_read_u8(input);
    22. }
    Alles anzeigen


    Der Thread wird gestartet und die "checkForMessages" Methode wird ausgeführt.
    In dem Fall versucht es immerwieder 4 bytes zu lesen die empfangen wurden.

    Wenn ein Byte noch nicht angekommen ist (z.B: das c2) dann stallt/wartet der ganze Thread und wird erst an der stelle (an dem er auf das byte wartet) fortgeführt wenn das byte ankommt.
    Das ist in der hinsicht praktisch, da du dadurch automatisch einen Queue/warte mechanismus erhälst und dich nicht darum kümmern musst ob nun ein byte wirklich angekommen ist um dieses zu lesen.
    Der Nachteil natürlich ist dass du pro client einen eigenen Thread brauchst der die TCP kommunikation übernimmt (willst du pro client noch andere operationen durchführen die nicht von den TCP nachrichten abhängen, dann wirst du weitere Threads brauchen.)
    Wenn ein fehler/disconnect auftritt wird eine exception geworfen und du kannst dann den thread dementsprechend beenden.
  • Du bist genial :)

    Ich habs nicht direkt so gemacht, da ich über meine Funktion ja ein DataInputStream einfach nur zurück gebe und nicht diesen direkt auslese.
    Trotzdem habe ich einfach einfach den ersten Byte ausgelesen, diesen mit dem ganzen Stream in einen byte Array gezogen und dieses wiederum in ein DataInputStream umgewandelt und dies dann returned. Dabei habe ich dann natürlich einen try-catch Block drum herum:

    Java-Quellcode

    1. try {
    2. DataInputStream dis = new DataInputStream(sock.getInputStream());
    3. byte b = dis.readByte();
    4. byte[] buff = new byte[dis.available()+1];
    5. buff[0] = b;
    6. dis.read(buff,1,dis.available());
    7. DataInputStream newDis = new DataInputStream(new ByteArrayInputStream(buff));
    8. return newDis;
    9. } catch (Exception e) {
    10. closeSocket(sock);
    11. }
    12. return null;
    Alles anzeigen

    Danke danke danke :)

    Freut euch auf schon mal auf ein Tag (evtl. mehrere Tage) wo ich dann endlich JEN vorzeigen kann!
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe