Sockets II



  • Hallo,

    schon wieder ich. 🙂

    Ich bin grad am rumprobieren, was so geht mit Sockets und habe folgendes Problem:

    Ich will einen Server bauen, der Clients akzeptiert, aber den Clients nur Daten sendet. (Ich nutze den Socket nur unidirektional) Es werden von den Clients keine Daten akzeptiert.

    Ich dachte mir mit einem einfachen shutdown(SHUT_RD) im Server mach ich dem Client schon mal klar, dass ich nichts von ihm will. Der client kann (leider) weiter munter drauflos senden, ohne dass er einen Fehler bemerkt. Ausserdem stellt sich für den Server das Problem, dass ich nicht mehr mitbekommt, wenn der Client die Verbindung unterbrochen hat.

    Anscheinend bin ich mit dem shutdown() auf dem völlig falschen Dampfer. Hat jemand eine Idee wie ich das Problem lösen kann? Oder geht das gar nicht?

    Gruß Chris



  • schließ doch die verbindung wenn sie was senden?



  • Chris2103 schrieb:

    ... shutdown(SHUT_RD) im Server mach ich dem Client schon mal klar, dass ich nichts von ihm will.

    Hi Cris,

    schon wieder ich 😉

    Kurz nach Deinem Problem ge-googled und fündig geworden:
    Der shutdown(SHUT_RD) bewirkt beim TCP-Protokoll offenbar nichts und der Client bemerkt davon nichts 😢

    Der shutdown(SHUT_WR) vor einem abschließenden close() bewirkt, dass die letzten Daten noch rausgeschickt werden (das ist meine Erfahrung, ich nehme SHUT_RDWR). Meistens klappt's für den Rest auch ohne shutdown(), aber halt nur meistens.

    So ich hätte jetzt zwei Möglichkeiten für Deine Problemstellung anzubieten:

    (1) Der Server beachtet den Eingabekanal nicht. Hierfür einfach vorm select() den Kanal deaktivieren. Folge => Wenn der Client sendet, blockiert er (wenn blockierender Modus gesetzt ist). Alternativ kann man beim Client den Sende-Kanal auf nicht-blockierend setzen (muss dann aber mit low-level Routinen arbeiten und muss auch sonst einiges bedenken) oder man setzt einen Timeout auf den Sendekanal mittels setsockopt().

    (2) Der Server beachtet den Eingabekanal und schmeißt alles in den Müll. Also einfach lesen und vergessen. Ist auch eine einfache Variante mit dem Vorteil => Client blockiert nicht beim Senden. Ist auch schnell und kostet nicht wirklich viel CPU-Zeit.

    Das Schließen nur einer Richtung des Sockets wird wohl nicht funktionieren. Denn Sinn eines Sockets ist ja gerade der bidirektionale Datenverkehr.

    Auf Seiten des Servers bekommst Du mit, wenn der Client den Socket geschlossen hat, entweder durch
    (a) beim Senden erhält der Server einen Fehler mit errno == EPIPE oder
    (b) beim Lesen erhälst Du einen Return-Wert mit geringerem Bytecount als erwartet oder halt einen Return-Wert von 0.

    P.S.: Das ganze Socket-Geschäft ist nicht ganz trivial (das hast Du wohl inzwischen auch gemerkt ;-). Gerade Server-seitig ist da viel Gehirnschmalz (inkl. Erfahrung und Recherche) reinzustecken. Ich empfehle, Server-seitig mit low-level Routinen, d.h. z.B. read(2) bzw. write(2), in beide Richtungen (read/write) im non-blocking Modus zu fahren und empfangsseitig mit select() zu arbeiten. Anderenfalls kommt man über kurz oder lang in Blockadesituationen, weil ein Kanal nichts mehr abnimmt oder nicht genug sendet, so dass der Server nicht mehr reagiert und alles steht. Wie gesagt, kann lange Zeit gut gehen, aber in irgendwelchen komischen Lastsituationen steht dann alles. Also: Alle blockierenden Aufrufe (insbesondere fwrite(), fprintf() usw.) entfernen. Allenfalls fprintf() für File-IO zum Debugging/Tracing/Logging nutzen.

    ... und wenn man dann mit den low-level Routinen arbeitet, muss man asynchrone Interrupts, wie z.B. mit errno==EINTR (aber da gibt's systemabhängig auch noch mehr) abfangen. Aber: immer mutig ran ans Werk 😉



  • Danke für die Antworten...


Anmelden zum Antworten