Problem bei select()
-
Ich will mit select mein Programm warten lassen, bis der User eine Eingabe macht oder bis ein Client sich über TCP zu meinem Server connected (Listenersocket). Ich will keine Zeit haben. Mein Programm sieht nun folgendermaßen aus:
ServerSocket a(1234); fd_set listenfds, masterfds; FD_ZERO(&listenfds); FD_SET(0,&listenfds); //auf stdin warten FD_SET(a.getSocket(),&listenfds); while(1) { //memcpy(&masterfds, &listenfds, sizeof(fd_set)); masterfds=listenfds; cout << "Stdin: " << fileno(stdin) << " Socket: " << a.getSocket() << endl; if(int i=select(a.getSocket()+1,&masterfds,NULL,NULL,NULL)>=1) { if(FD_ISSET(fileno(stdin),&masterfds)) //Usereingabe! { char eingabe=fgetc(stdin); if(eingabe=='x' || eingabe =='X') { a.closeSocket(); cout << "Server wurde vom User terminiert!" << endl; exit(0); } else cout << "Geben Sie X zum Beenden ein!" << endl; } if(FD_ISSET(a.getSocket(), &masterfds)) //sollte beide Ereignisse gleichzeitig eintreten! { } else continue; } else { cout << "Fehler bei select(): " << i << endl; //genau hier gibt select() immer 0 zurück continue(); } Socket s=a.wait4client(); //warte auf einen Client #if METHOD == FORK switch(fork()) { //Child-Prozess: case 0: a.closeSocket(); //Listenersocket schließen bediene_client(s); s.closeSocket(); exit(0); //beende den Childprozess case -1:cout << "Fehler bei fork()" << endl; s.closeSocket(); //Client konnte nicht angenommen werden! break; //Parent-Prozess: default:s.closeSocket(); //Clientsocket schließen break; } }
Das Problem ist jetzt, dass select() 0 zurückgibt (das gibt er nur zurück, wenn der Timeout abgelaufen ist, ich habe aber keinen Timeout!!), wenn ein Ereignis eintritt!!! Dies gibt er aber erst zurück, nachdem der Client abgefertigt wurde. Prinzipiell wartet er auf beide Sockets problemlos.
Die Klassen ServerSocket und Socket sind nur Wrapperklassen für die TCP Kommunikation. Die Konstruktoren rufen lediglich die C-Funktionen socket() bind() und listen(). Die Memberfunktion wait4client() ruft accept() auf und gibt eine Instanz der Klasse Socket zurück, über der dann die Daten empfangen bzw. verschickt werden. a.getSocket() liefert den Listenfiledeskriptor zurück, wo die eingehenden Verbindungen hereinkommen.
Was muss ich also tun, um diesen Fehler wegzubekommen. Ich weiß, dass es funktioniert, jedoch schreibe ich in einem Team ein professionelles Programm (das ich auch dann abgeben muss), und da macht es sich nicht gut, wenn bei der Ausgabe immer ein Fehler angezeigt wird!!
-
Mal so auf die Schnelle:
Du darfst FD_SET() nur dort machen, wo du auch eine Eingabe erwartest. Wenn also der Client abgefertigt wurde, läßt Du ein einfach das FD_SET() für diesen fd weg. Im Prinzip gibt es auch noch eine Antwort auf diesem Kanal, wenn der Client den Kanal dichtgemacht hat (also beim EOF).
Die ganze Sequenz FD_ZERO, FD_SET sollte also in die while-Schleife rein!
Könnte das das Problem lösen?