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.
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 :(
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.
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 :(
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.
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. :)
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();
}
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....