Maxwell: Sockfehler merken

Hallo,

ich überlege mir gerade, wie man ein Client/Server über Sockets "ausfallsicher" macht. Ich meine: ein Client ist über lange Zeit mit dem Server verbunden. Teilweise könnte die Verbindung (z.B. Netzwerkverbindung hardwaretechnisch getrennt, Server neustart, etc.) abbrechen. Jetzt muss der Client ja merken, wann eine Verbindung abgebrochen ist. Das wird soweit ich weiss normalerweise über Signale oder Fehlermeldungen gemacht: Entweder der Client erhält beim senden ein SIGPIPE (schreiben auf geschlossene Verbindung), oder er erhält beim Lesen und errno (C Fehler). Ist das schon alles? Oder wäre es klug noch ein Timeout über alarm() zu erstellen: falls eine Sekunde nix passiert => Verbindungen erneut herstellen, ansonsten Fehlerbehebung aufrufen o.ä. Beim SIGPIPE noch ne Frage: wie finde ich heraus, welche Verbindung davon betroffen ist???

Grüsse,

Maxwell

  1. Hallo Maxwell,

    ich überlege mir gerade, wie man ein Client/Server über Sockets "ausfallsicher" macht.

    du meinst TCP-Sockets.

    Ich meine: ein Client ist über lange Zeit mit dem Server verbunden.

    du meinst: Dein Client-Programm, geschrieben offensichtlich in C (dem Folgenden entnommen), mit einem Server. Falsche Kategorie - kein Wunder, dass keiner antwortet :/

    Teilweise könnte die Verbindung (z.B. Netzwerkverbindung hardwaretechnisch getrennt, Server neustart, etc.) abbrechen.

    deswegen nutzt du ja auch ein TCP/IP-Socket und kein UDP/IP-Socket. Um zu erkennen, ob die Daten ankommen oder ob die Verbindung noch lebt.

    Jetzt muss der Client ja merken, wann eine Verbindung abgebrochen ist. Das wird soweit ich weiss normalerweise über Signale oder Fehlermeldungen gemacht: Entweder der Client erhält beim senden ein SIGPIPE (schreiben auf geschlossene Verbindung), oder er erhält beim Lesen und errno (C Fehler). Ist das schon alles?

    Nicht ganz.

    [ich beziehe mich nur auf Unix BSD-Sockets, die Windows-API ist etwas anders, aber im Prinzip gleich]

    Beim Lesen von einem Socket stehen verschiedene Funktionen zur Verfügung (siehe <man recv>); mit der üblichen recv() kannst du den Fehler in der Tat nur über errno auslesen (Fehlerbeschreibungen gibts z.B. auf <man tcp> und <man ip>). Benutzt du alternativ recvmsg, kriegst du im Endeffekt die gleichen Informationen, nur halt in einer C-Struktur verpackt (siehe manpage).

    Beim Senden gibt es genauso Fehler über errno (siehe <man send>), dass der Prozess ein SIGPIPE-Signal erhält, kannst du bei deinem Socket auch im Programm ausstellen (wenn man mehrere oder parallele Sockets benutzt, oder bei einem Serverprogramm, ist das vielleicht wünschenswerter, als sich völlig asynchron mit Signalen rumzuschlagen).

    Oder wäre es klug noch ein Timeout über alarm() zu erstellen: falls eine Sekunde nix passiert => Verbindungen erneut herstellen, ansonsten Fehlerbehebung aufrufen o.ä.

    Üblicherweise sind die "Timeouts" über TCP systemweit definiert: Wenn in x Sekunden kein ACK ("Packet erhalten") für ein versandtes Datenpacket kommt, gilt das Packet z.B. als nicht angekommen und wird nochmal verschickt. Diese systemweiten Einstellungen für sein Programm zu ändern macht nur bedingt Sinn: Man kann sie ja eben Systemweit anpassen (bei Linux z.B. über sysfs, üblicherweise sowas wie (/proc)/sys/net/ipv4/), um auf umgebungsspezifische Besonderheiten einzugehen. Z.B. wenn man weiß, dass bei der Netzwerkverbindung alles ein bisschen länger dauert.

    Beim SIGPIPE noch ne Frage: wie finde ich heraus, welche Verbindung davon betroffen ist???

    afaik gar nicht. Deswegen kannst du ja eben verhindern, dass SIGPIPE benutzt wird. Z.B. so:

      
      int return_code;  
      if((return_code = send(dein_socket, deine_daten, laenge, MSG_NOSIGNAL)) < 0) {  
          puts("Senden ging wohl nicht.\n");  
          if(return_code == EPIPE) {  
              puts("Und zwar weil das Socket tot ist.\n"  
                   "Und jetzt weiß ich sogar, welches Socket tot ist.");  
              loesche_verbindungsdaten();  
              starte_neue_verbindung();  
          } else /* ... */  
      }  
    
    

    Grüße,

    Sven

    1. Hallo Sven,

      vielen Dank für die Antwort. War für mich sehr hilfreich!

      Welche Kategorie sollte ich dann nehmen???

      Grüsse,

      Maxwell

      1. Hallo Maxwell,

        vielen Dank für die Antwort. War für mich sehr hilfreich!

        danke :)

        Welche Kategorie sollte ich dann nehmen???

        Kategorie? Man-Page-Kategorie? Funktions-"Kategorie"? Was meinst du?

        Grüße,

        Sven

        --
        ich hatte mal meterlange signs, die sind alle weg