Socketprobleme: erkennen, ob Client weg ist



  • Hi,

    Ich habe einen Serversocket, der die Sockets aller eingehenden Verbindungen auf non-blocking setzt (das geht nicht anders, da die eingehenden Datenpackete eine nicht vorhersehbare Größe haben und ein recv() nicht alles blockieren soll, nur weil ein paar Bytes fehlen).

    Mittels select() überprüfe ich, ob irgend welche Daten anstehen. Wenn das der Fall ist, lese ich diese Daten vom ensprechenden Socket. Erhalte ich dabei nicht die Maximalanzahl von Daten, sondern bekomme einen Fehler EAGAIN, so weiß ich, dass kein grundsätzliches Problem vorliegt, sondern die entsprechenden Daten einfach noch nicht da sind.

    Anders aber, wenn der Client seine Verbindung schließt, jetzt erzählt mir select() ständig, dass Daten zum empfang anstehen, wenn ich versuche, diese zu lesen, bekomme ich immer nur ein EAGAIN.

    Wie kann ich jetzt herausfinden, ob ein Clientsocket wirklich noch lebt? Die Bedingung, dass select() sich meldet, trotzdem aber 0 Bytes gelesen werden können sind in beiden Fällen ja gleich. recv() arbeitet übrigens mit MSG_NOSIGNAL, die auswertung der MEssages würde ich mir nämlich gerne ersparen...



  • Also ich überprüfe mit recv immer, wieviele Daten reingekommen sind. Wenn es 0 bytes sind, dann heißt es dass die Gegenseite die Verbindung geschlossen hat. Danach kannst du deinen entsprechenden Socket Serverseitig auch schließen.

    Hilft dir das oder habe ich dich falsch verstanden?



  • Das hilft bei nichtblockierenden Sockets leider gar nix - hier kommen auch bei offener Verbindung ein paar mal 0 Bytes an, wenn zuvor was empfangen wurde.



  • Was ist mit der Fehlermeldung:

    ENOTCONN
    The socket is associated with a connection-oriented protocol and
    has not been connected (see connect(2) and accept(2)).

    Vielleicht könnte die dir helfen? Wenn die Verbindung geschlossen wurde, dann müsste das ja so funktionieren.



  • Nope, es kommt spannenderweise ausschließlich EAGAIN. Und der Remote-Client ist definitiv weg, da nehme ich zum Testen einen Telnet-Client, den ich jedes mal komplett zumache.



  • recv() nicht alles blockieren soll

    Du kannst ja einen eigenen Thread/Prozess dafuer erstellen. Ausserdem gibt es auch gute Tutorials wie man mit select() einen multimillion Connection Client recht einfach ohne zusaetzliche Threads bastelt. Ausserdem solltest du TCP verwenden, weil das verbindungsorientiert ist und dein gesuchtes Feature von Haus aus mitbringt.



  • knivil schrieb:

    recv() nicht alles blockieren soll

    Du kannst ja einen eigenen Thread/Prozess dafuer erstellen. Ausserdem gibt es auch gute Tutorials wie man mit select() einen multimillion Connection Client recht einfach ohne zusaetzliche Threads bastelt. Ausserdem solltest du TCP verwenden, weil das verbindungsorientiert ist und dein gesuchtes Feature von Haus aus mitbringt.

    Sorry, aber das bringt mich keinen Schritt weiter:

    - eigene Threads fallen Weg, da es einfach zu viele Clients mit Minianfragen sein können, der Overhead durch eigene Threads wäre Wahnsinn
    - select() kenne ich, es liefert bereits jetzt die Information zurück, dass Read-Daten anstehen - was bei nicht-blockierenden Sockets nichts bringt, da ein anschließendes recv() mit 0 Bytes keine Aussagekraft hat (es können 0 Bytes sein, weil die Daten noch nicht zur Verfügung stehen oder 0 Bytes, weil der Client zugemacht hat)
    - TCP...ja, nee, schon klar - was glaubst du, was ich mache? Buschtrommeln?



  • EAGAIN bedeutet: der socket steht auf nicht blockierend und es sind keine daten vorhanden.
    wenn der client die verbindung schliesst wird errno auf ECONNRESET gesetzt nach einem recv.

    siehe http://www.opengroup.org/onlinepubs/009695399/functions/recv.html

    wird die verbindung unterbrochen, d.h. client schliesst die verbindung nicht bzw kann sie nicht schliessen, bekommst du das so ohne weiteres nicht mit. da müsstest du eine art alive paket einbauen. z.b. alle x sekunden versendet der server ein paket. kommt keine antwort vom client ist der tot.



  • TomoT schrieb:

    - select() kenne ich, es liefert bereits jetzt die Information zurück, dass Read-Daten anstehen - was bei nicht-blockierenden Sockets nichts bringt, da ein anschließendes recv() mit 0 Bytes keine Aussagekraft hat (es können 0 Bytes sein, weil die Daten noch nicht zur Verfügung stehen oder 0 Bytes, weil der Client zugemacht hat)

    wenn select zurückkehrt, ohne fehler, sind entweder daten vorhanden oder es ist "etwas passiert". soll heissen recv meldet der client hat die verbindung geschlossen oder es ist ein fehler aufgetreten.
    du solltest für den fall das daten vorhanden sind auch mindestens 1 byte lesen können. d.h. daten vorhanden und 0 bytes geht nicht.



  • ihoernchen schrieb:

    du solltest für den fall das daten vorhanden sind auch mindestens 1 byte lesen können. d.h. daten vorhanden und 0 bytes geht nicht.

    Das war doch mal ein heißer Tipp - der Returnwert von recv() ist tatsächlich anders. Wenn select() zurückkommt, weil der Client gerade geschlossen wurde, liefert recv() 0 zurück. Kann hingegen nichts mehr vom Client gelesen werden, ist der Returnwert von recv() -1 - mit dem EAGAIN-Fehlercode...

    Thx für den Hinweis!


Anmelden zum Antworten