Pain-maker
Mitglied
Hi @ all
Hab da mal wieder son Problem und glaube dass ich da nen Denkfehler hab... Nur leider komm ich nich drauf. Hab jetzt schon ewig rumprobiert, aber es klappt einfach nicht.
Ich poste mal zu Beginn einen Auszug des Quellcodes:
(Hab mal meine Versuche, bzw. die funktionierende Form auskommentiert mit gepostet)
Ich starte einen Server, der dann in einem gesonderten Thread via select() neue Clienten annimmt und diese verarbeitet. Nun brauchte ich dabei immer 2 weitere Schleifen in der Hauptschleife, was die Annahme von neuen Clienten via accept() verlangsamte. Daher dachte ich ich könnte das einfach in einen gesonderten Thread auslagern, aber klappt leider nicht richtig, Bei langsam hintereinander gestellten Anfragen klappt alles, aber wenn ich das Tempo erhöhe oder mehrere Anfragen gleichzeitig stelle, dann bricht die Verbindung einiger Clienten beim Lesen ab. (Ich teste mit ApacheBenchmark)
Das Verarbeiten läuft hier ab:
(Ursprünglich sollte das mal in einem Threadpool ausgeführt werden)
Nebenbei bin ich mir auch bei der Threadsicherheit nich mehr so ganz sicher.
Wäre jedem Dankbar, der mir mal ne Fehlerkorrektur und Aufklärung geben könnte
Mfg Pain-maker
Hab da mal wieder son Problem und glaube dass ich da nen Denkfehler hab... Nur leider komm ich nich drauf. Hab jetzt schon ewig rumprobiert, aber es klappt einfach nicht.
Ich poste mal zu Beginn einen Auszug des Quellcodes:
(Hab mal meine Versuche, bzw. die funktionierende Form auskommentiert mit gepostet)
PHP:
/**
* startServerAsync
*/
bool MySocketServer::startServerAsync(void (*fkt)(MySocket *fkt, void *param), void *param)
{
sockaddr_in sa;
UINT_PTR ret;
unsigned int i = 0;
this->callback = fkt;
this->callbackParam = param;
// IP konfigurieren
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(this->port);
sa.sin_addr.s_addr = INADDR_ANY;
// Neue Socket erstellen
this->hndl = socket(AF_INET, SOCK_STREAM, 0);
if(this->isValid() == false)
throw "INVALID_SOCKET";
// Socket an IP binden
if(bind(this->hndl, (SOCKADDR*)&sa, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
closesocket(this->hndl);
throw "INVALID_SOCKET";
}
// Auf eingehende Verbindungen warten
if(listen(this->hndl, this->maxConnections) == SOCKET_ERROR)
{
printf("Fehler: listen, fehler code: %d\n", WSAGetLastError());
return true;
}
// Clients initialisieren
try
{
this->clients = new MySocket[this->maxConnections];
this->clientWorker = new MySocketServerWorker[this->maxConnections];
if(this->clients == NULL)
throw 1;
// Socket-Handles ungültig machen
for(i=0; i<this->maxConnections; i++)
this->clients[i].setInvalid();
}
catch(...)
{
// Kein Speicher mehr verfügbar / Fehler bei der Speicherreservierung
return false;
}
// Serverthread starten
this->threadStatus = THREAD_RUNNING;
ret = _beginthreadex(NULL, 0, &MySocketServer::serverThread, (void*)this, 0, NULL);
if(ret != NULL)
ret = _beginthreadex(NULL, 0, &MySocketServer::acceptThread, (void*)this, 0, NULL);
if(ret == NULL)
{
this->threadState = THREAD_STOPPED;
return false;
}
return true;
}
/**
* serverThread
*/
int MySocketServer::serverThread(void *ptr)
{
MySocketServerWorker *worker = NULL;
MySocketServer *server = (MySocketServer*)ptr; // this-Pointer
SOCKET clientSocket = INVALID_SOCKET;
fd_set *fdSet = &server->fds;
unsigned int i = 0;
int ret = 0;
struct sockaddr_in addr_in;
socklen_t addr_len = sizeof(addr_in);
while(server->threadStatus == THREAD_RUNNING)
{
// Server-Loop
FD_ZERO(fdSet); // Inhalt leeren
FD_SET(server->hndl, fdSet); // Den Socket der Verbindungen annimmt hinzufügen
/*
// Neue Verbindungen registrieren
for(i=0; i<server->maxConnections; i++)
{
if(server->clients[i].isValid())
FD_SET(server->clients[i].getHandle(), fdSet);
}
*/
// Auf Änderungen prüfen
ret = select(0, fdSet, NULL, NULL, NULL);
if(ret == SOCKET_ERROR)
{
//printf("Fehler: select(), error code: %d\n", WSAGetLastError());
//return 0;
continue;
}
// Server-Socket überprüfen -> Verbindung annehmen (sofern noch freie Verbindungen verfügbar sind)
if(FD_ISSET(server->hndl, fdSet))
{
for(i=0; i<server->maxConnections; i++)
{
// Auf freien Worker prüfen und diesen sperren
if(server->clientWorker[i].lock())
{
// Neuen Clienten annehmen
clientSocket = accept(server->hndl, (struct sockaddr*)&addr_in, &addr_len);
if(clientSocket != INVALID_SOCKET)
{
server->clientWorker[i].setClient(&server->clients[i]);
server->clientWorker[i].setParam(server->callbackParam);
server->clientWorker[i].setCallback(server->callback);
server->clients[i].setHandle(clientSocket);
}
else
{
server->clientWorker[i].unlock();
printf("ERROR! Failed to accept client\n");
}
break;
}
}
// Keine freien Verbindungen
if(i == server->maxConnections)
{
printf("WARNING! Too many connections!\n");
}
}
/*
// Neue Anfragen beabreiten
for(i=0; i<server->maxConnections; i++)
{
if(!server->clients[i].isValid())
continue;
// Anfrage verarbeiten
if(FD_ISSET(server->clients[i].getHandle(), fdSet))
{
server->clientWorker[i].run();
}
}
*/
}
// Serverthread beendet
server->threadStatus = THREAD_STOPPED;
return 0;
}
/**
* acceptThread
*/
int MySocketServer::acceptThread(void *ptr)
{
MySocketServerWorker *worker = NULL;
MySocketServer *server = (MySocketServer*)ptr; // this-Pointer
SOCKET clientSocket = INVALID_SOCKET;
unsigned int i = 0;
int ret = 0;
fd_set myFds;
fd_set *fdSet = &myFds;
//fd_set *fdSet = &server->fds;
// Server-Loop
while(server->threadStatus == THREAD_RUNNING)
{
FD_ZERO(fdSet);
// Neue Verbindungen registrieren
for(i=0; i<server->maxConnections; i++)
{
if(server->clients[i].isValid())
FD_SET(server->clients[i].getHandle(), fdSet);
}
// Auf Änderungen prüfen
ret = select(0, fdSet, NULL, NULL, NULL);
if(ret == SOCKET_ERROR)
{
//printf("Fehler: select(), error code: %d\n", WSAGetLastError());
//return 0;
continue;
}
// Neue Anfragen beabreiten
for(i=0; i<server->maxConnections; i++)
{
if(!server->clients[i].isValid())
continue;
// Anfrage verarbeiten
if(FD_ISSET(server->clients[i].getHandle(), fdSet))
{
server->clientWorker[i].run();
}
}
}
// Serverthread beendet
server->threadStatus = THREAD_STOPPED;
return 0;
}
Ich starte einen Server, der dann in einem gesonderten Thread via select() neue Clienten annimmt und diese verarbeitet. Nun brauchte ich dabei immer 2 weitere Schleifen in der Hauptschleife, was die Annahme von neuen Clienten via accept() verlangsamte. Daher dachte ich ich könnte das einfach in einen gesonderten Thread auslagern, aber klappt leider nicht richtig, Bei langsam hintereinander gestellten Anfragen klappt alles, aber wenn ich das Tempo erhöhe oder mehrere Anfragen gleichzeitig stelle, dann bricht die Verbindung einiger Clienten beim Lesen ab. (Ich teste mit ApacheBenchmark)
Das Verarbeiten läuft hier ab:
(Ursprünglich sollte das mal in einem Threadpool ausgeführt werden)
PHP:
/**
* run
*/
void MySocketServerWorker::run()
{
if(this->running == false)
{
this->running = true;
// Anfrage behandeln
char dummy[512];
this->client->receiveBytes(dummy, sizeof(dummy));
this->client->sendBytes("HTTP/1.0 200 OK\n\n");
this->client->close();
/*
this->callback(this->client, this->param);
*/
this->unlock();
this->running = false;
}
}
Nebenbei bin ich mir auch bei der Threadsicherheit nich mehr so ganz sicher.
Wäre jedem Dankbar, der mir mal ne Fehlerkorrektur und Aufklärung geben könnte

Mfg Pain-maker
Zuletzt bearbeitet: