Sockets



  • Hallo,

    eine Frage zum Theam Sockets. Gibt es eigentlich eine Möglichkeit bei einem Server Socket festzulegen, wieviele Clients maximal angenommen werden? Alle weiteren Clients sollen dann abgewiesen werden.

    Beispiel: Bei einem einachen Server (siehe Code-Schnipsel) sollte so lange wie do_something() ausgeführt wird, jeder neue Client abgewisen werden. Bei meinen Test warten weitere Clients einfach so lange bis der vorherige Client fertig ist, und stellen dann die Verbindung fertig. Kann man das abstellen?

    Server Code Schnipsel:

    while (true)
    {
      int client_fd = accept(server_fd, ....);
      do_something(client_fd);
    }
    

    Danke schon mal,

    Chris



  • Da mußt du schon vor Aufruf des accept() einen Test machen.



  • du könntest beim aufruf von 'listen()' den parameter 'backlog' auf 0 setzen. der gibt an, wieviele connects in der warteschlange gehalten werden...



  • Beide vorgeschlagenen Methoden

    (1) beim accept einfach nur zu zählen oder
    (2) backlog auf 0 setzen

    haben Ihre Tücken.

    Die Backlog-Einstellung dient dazu, Connect-Requests in einer Wartequeue (Länge=backlog-Einstellung, wird beim listen() eingestellt) zu puffern und nicht gleich abzuweisen. Die Wartequeue muss so groß sein, dass die Zeit überbrückt wird, bis der Server wieder einen neuen Accept durchführen kann. Ist die Backlog-Einstellung zu gering und ist der Server zu beschäftigt, werden folglich Connect-Requests auch unbegründet abgewiesen, obwohl die maximale Anzahl noch nicht erreicht ist. Daher ist ein Backlog von 0 - sagen wir mal - "ungünstig".

    Nur einfach beim accept() zu zählen, reicht auch nicht, sondern es bedarf da noch weiterer Maßnahmen.

    Also mal ein Fall aus der Praxis, wie ich es bei einem Applicationserver geregelt habe:

    Ich habe nur einen begrenzte Anzahl von Resourcen, sagen wir mal 500. Beim accept() überprüfe ich, wieviele der Resourcen belegt sind. Komme ich an eine Grenze, also z.B. an die 500, so setze ich einen (globalen) Merker, dass ich beim select()-Aufruf den entsprechenden Kanal (auf dem der listen()/accept() horcht) deaktiviere, d.h. ich beachte den Inputkanal nicht weiter, kann aber alle anderen Aktivitäten, inbesondere I/O-Aktivitäten, weiter durchführen.
    Noch weitere anliegende Connect-Requests können sich jetzt in der Wartequeue aufstauen bis zum BACKLOG-Limit und werden erst dann abgewiesen. Führe ich das Deaktivieren des Inputkanals nicht durch, so werde ich mit permanenten accept()-Aufrufen vollgeballert (auch wenn nur ein weiterer Connect-Request anliegt) und werde dann nicht wirklich glücklich.

    Im zweiten Schritt muss ich natürlich überprüfen, wenn meine Resourcen wieder frei werden. Wenn ich jetzt also etwa 100 meiner Resourcen wieder frei habe (also 400 belegte), gebe ich den Inputkanal wieder für den select()-Aufruf frei und das Spiel kann von vorne beginnen.

    In der so beschriebenen Art machen es die meisten Web-Server und Application-Server. Die nicht bedienten Clients bekommen dann automatisch einen Timeout (wie z.B. bei einem HTTP-Request).

    Ich nehme an, der Hintergrund deiner Frage liegt ebenfalls in der begrenzten Anzahl von Resourcen. Nach der oben beschriebenen Methode kann man den Backlog-Bereich also auch entscheidend größer anlegen, ich habe ihn z.B. auf den 4-fachen Wert der Resourcenanzahl eingestellt.



  • Danke für die Antworten,

    die Antwort von Jox ist wohl das was ich brauche. Zwei Fragen zum Timeout habe ich noch.

    1. Wird der Timeout im Server gesetzt, oder muss der Client beim Verbindungsaufbau den Timeout setzen. Ich will vermeiden, dass ein Client endlos auf die Verbindung wartet, bzw. wenn die Resourcen alle belegt sind.
    2. Wie setzt man den Timout (Syntax, Funktionnen)? 🙂

    Gruss Chris.



  • Chris2103 schrieb:

    Wie setzt man den Timout (Syntax, Funktionnen)? 🙂

    Timeouts sollte man auf Client-Seite setzen können mit setsockopt(), entweder mit SO_SNDTIMEO fürs Senden oder SO_RCVTIMEO fürs Lesen (oder beides). Damit müßtest Du Dein Problem lösen können. Ich habe aber beides in dem von mir beschriebenen Zusammenhang selbst nicht benutzt (kann daher nicht auf die Schnelle mit einem funktionierenden Beispiel dienen). Ich schätze mal, dass es unsinnig ist, serverseitig ein Timeout zu setzen (der Datenkanal steht erst nach dem accept() zur Verfügung, und auf dem listen/accept-socket macht serverseitig ein Timeout nun wirklich keinen Sinn).

    Wenn ich die (linux)-manual-pages richtig interpretiere, bekommt man nach Aktivierung der Timeout-Option und Eintreten eines Timeouts als Return-Wert entweder
    (a) einen anderen Bytecount als die zu übertragende bzw. zu emfangende Anzahl zurück oder
    (b) einen negativen Wert (-1) und als errno EAGAIN (write-Richtung) oder EWOULDBLOCK (read-Richtung) zurück.

    In der Regel hat man aber auch keinen Bedarf, einen Timeout auf Client-Seite setzen zu müssen. Nach der von mir beschriebenen Methode läuft das folgendermaßen: Wenn die Resourcen nicht zur Verfügung stehen, wartet der Client, bis wieder etwas frei wird.

    Alternativ zum obigen Timeout kann man allerdings bei Erreichen des Resourcen-Limits auch weitere Connect-Requests annehmen und sofort serverseitig eine qualifizierte Return/Error-Message an den Client zurücksenden (vorausgesetzt, die zu verwaltenden Resourcen sind nicht ausgerechnet Filedescriptoren, so dass man gar keine accept()'s mehr korrekt durchführen kann 😉


Anmelden zum Antworten