Seite 1 von 1

Threaded bsd sockets

Verfasst: 08.04.2009, 02:28
von Halan
Hey,

ich hab eine kleinen Webserver geschrieben und versuche den jetzt mit threads skalierbar zu machen. Leider funktioniert das ganze nicht. Es scheint wenn der server eine Anfrage ausführt werden alle anderen abgelehnt.

Ich hab etz hier mal den code kopiert. Sollte eigentlich für sich selbst sprechen, fragt einfach wenn was unklar ist.

Code: Alles auswählen

void CWebServer::work()
{
    IServerProcess::work();

    s32 s = conn.accept();

    if (s >= 0)
    {
        try
        {
            boost::function0<s32> f = boost::bind( &CWebServer::serverThread, this, s, conn.getClientAddress());
            boost::thread td(f);
        }
        catch (exception& e)
        {
            Logger->log(ELMT_Warning, "Failed creating thread caused by: ", false);
            Logger->write(e.what());
        }
    }
}

s32 CWebServer::serverThread(s32 socket, string address)
{
    try
    {
        //! CWebServer is also the handler
        //! Debugging is disabled by default
        CHttp http(this, address, false);

        http.parseRequest(socket);

        conn.close(socket);

        return 0;
    }
    catch (exception& e)
    {
        Logger->log(ELMT_Warning, "Failed processing Request caused by: ", false);
        Logger->write(e.what());

        return -1;
    }
}

Re: Threaded bsd sockets

Verfasst: 08.04.2009, 09:04
von Jörg
Mit welchen Parametern rufst Du listen() auf dem Socket von 'conn' auf ?
Es scheint wenn der server eine Anfrage ausführt werden alle anderen abgelehnt.
Es scheint klingt als ob Du Dir nicht sicher bist...was sind die Symptome?

Re: Threaded bsd sockets

Verfasst: 08.04.2009, 13:49
von Halan
Okay, ein paar der Probleme hab ich jetzt abgefangen weil ich wohl EWOULDBLOCK nicht gehandelt hab.

Aber trotzdem bekomme ich manchmal wenn ich mehrmals hintereinander anfrage in Firefox:
"Verbindung unterbrochen: Die Verbindung zum Server wurde zurückgesetzt, während die Seite geladen wurde."

EDIT: Okay ich denk ich hab das Problem:
Es kann ja sein dass der Client disconnected (send/recv also 0 zurückgeben) ich rufe aber trotzdem conn.close(socket); auf. Jetzt kann der fd ja schonwieder vergeben sein oder nicht? Und dann schließe ich die neueVverbindung.
Jetzt muss ich nur überlegen wie ich das fixe.

Jetzt spiel ich mit dem gedanken das ganze über fork() zu machen. Mit threads hab ich iwie immer nur probleme. Oder select() und die threads weg zu lassen, aber dann scheint das ganze nicht skalierbar genug :(

Re: Threaded bsd sockets

Verfasst: 08.04.2009, 15:12
von odenter
Ohne Threads wirds nicht gehen.

Wenn Du auf Port 80 horchst, dann machst Du bei jeder eingehenden Verbindung einen neuen Thread in dem jeder einzelne Client behandelt wird. Wenn der Client (oder wer auch immer) die Verbindung beendet, dann beendest auch Deinen Thread.

Du brauchst also ne Klasse ala

Code: Alles auswählen

class CClientHandler {
  private:
    bool isRunningValue = false;

  public:
    CClientHandler(Socket s) {
    }

    void Start() {
      isRunningValue = true;

      while (isRunningValue) {
      }
    }

    bool IsRunning() {
    }
}
Und die Start-Methode dann in einem Thread aufrufen und darin halt die Kommunikation machen, dann sollte alles ohne Probleme gehen.

Re: Threaded bsd sockets

Verfasst: 08.04.2009, 23:14
von Halan
danke für die antwort odenter.

Das ist ja im Prinzip das was ich schon mache.

Ich habe einen socket der nach einkommen verbindungen "guckt". Wenn ein client verbindet erstelle ich einen neuen thread mit einer handler klasse (=CHttp) udn übergebe ihr den socket.

Das ganze funktioniert auch ziehmlcih gut solang ich nicht während dem laden einer seite refreshe. Ich denke dann bricht der browser aprupt die verbindung ab. Iwas geht da mit den filedescriptors schief. Gibt es irgendwo ein tutorial das die thematik "sockets und threads" behandelt?
Das typische linux szenario wäre fork() aber das wollte ich in diesem fall eigentlich nicht verwenden :(

Re: Threaded bsd sockets

Verfasst: 09.04.2009, 08:17
von Jörg
Halan hat geschrieben: Es kann ja sein dass der Client disconnected (send/recv also 0 zurückgeben) ich rufe aber trotzdem conn.close(socket); auf. Jetzt kann der fd ja schonwieder vergeben sein oder nicht?
Nein, der fd wird fruehestens dann wiederverwendet, wenn er geschlossen wurde.
Hast Du beachtet, dass beim send u.U. nicht alles auf einmal uebertragen wird? Wenn du das nicht abfaengst, sondern einfach weitermachst, schliesst Du eine Verbindung, bei der die Gegenseite (Browser) noch Daten erwartet.
Das umsteigen auf fork wird in deinem Falle das Problem nicht loesen, das handling der sockets bleibt davon unberuehrt.

Re: Threaded bsd sockets

Verfasst: 09.04.2009, 09:11
von odenter
Halan hat geschrieben: Das ganze funktioniert auch ziehmlcih gut solang ich nicht während dem laden einer seite refreshe. Ich denke dann bricht der browser aprupt die verbindung ab. Iwas geht da mit den filedescriptors schief. Gibt es irgendwo ein tutorial das die thematik "sockets und threads" behandelt?
Das typische linux szenario wäre fork() aber das wollte ich in diesem fall eigentlich nicht verwenden :(
Wäre ja auch logisch wenn der Browser die Verbindung beendet. Du hast dem Browser ja gesagt er soll alles neu anfordern.

Man kann doch abfragen in welchem Status sich der Socket befindet. Sende halt nur Daten, wenn die Verbindung noch da ist.
Alternativ könnte man erstmal ein Try / Catch umzubauen und den Fehler einfach wegfischen, ist aber nicht gerade optimal. :)

Re: Threaded bsd sockets

Verfasst: 17.07.2009, 16:34
von Halan
Hab das ganze jetzt mit fork realisiert aber iwie funktioniert das noch nicht ganz (teile der Seite laden nie fertig)

Code: Alles auswählen

void CWebServer::work()
{
    IServerNode::work();

    s32 s = conn.accept();

    //! If the filedescriptor is valid we start a new thread
    if (s >= 0)
    {
        Logger->log(ELMT_Info, "New Web Request. Forking...");

        DatabaseManager->deactivate();

        s32 res = fork();

        if(res == 0)
        {
            DatabaseManager->activate();

            //! TODO: keep connections. ATM we just process one request and close the thread
            Logger->setLogToFile(false);
            Logger->setName("WebFork");
            this->writeUpdatesToDatabase(false);

            CHttp http(this, conn.getClientAddress(), false);
            http.parseRequest(s);

            conn.close(s);

            exit(0);
        }
        else if(res < 0)
            Logger->log(ELMT_Warning, "Something went wrong forking");

        DatabaseManager->activate();
    }

    //! Update the sessions
    //! We disconnect them after a 30 minute timeout
    SessionManager->work();
}

Re: Threaded bsd sockets

Verfasst: 20.07.2009, 10:30
von Jörg
conn.close(s); <-- was macht das ? Nur close() auf dem Socket aufrufen?

Dann koenntest Du in Probleme laufen, weil Du fork() verwendet hast, die genau in Symptomen resultieren, die Du beschreibst.
Versuch mal, vorher ein shutdown() auf dem Socket zu machen. close() laesst den Socket naemlich fuer andere Prozesse offen....

Re: Threaded bsd sockets

Verfasst: 20.07.2009, 18:38
von kimmi
Ich fand die folgende Seite recht nützlich:
http://www.beej.us/guide/bgnet/output/h ... index.html

Gruß Kimmi

Re: Threaded bsd sockets

Verfasst: 20.07.2009, 20:33
von Jörg
Leider erwaehnt diese aber mit keinem Wort das Verhalten von sockets im Falle von fork().

Daher, wenn's mal klemmt: http://www.faqs.org/faqs/unix-faq/socket/

Joerg