FD_SET und die Sockets
-
Hallo,
versuche grade sockets anhand des fd_set zu verwalten, also mehrere verbindungen annehmen etc.
das klappt bei der aller ersten verbindung wunderbar, sie wird angenommen, daten ausgetauscht und geschloßen sowie aus dem FD_SET entfernt.
Nur bei jedem weiteren Socket passiert gar nichts, irgendwie liefert der select immer SOCKET_ERROR zurück.Hier mal der code
Diese Routine nimmt die verbindungen an:
bool CTCPServer::CheckForNewConnection() { /* Prüft ob am AcceptSocket eine Verbindung aufgebaut wurde, wenn ja wird die Verbindung an einem freien Socket in Array aufgebaut, sofern noch 1 Platz frei ist. */ int iStatus = 0; bool freeSocketFound = false; iStatus = select(0, &(this->fdSet), NULL, NULL, NULL); if(iStatus != SOCKET_ERROR) { if(FD_ISSET(this->AcceptSocket, &(this->fdSet))) for(int i=0; i < MAX_CLIENTS_TO_CONNECT; i++) if(this->SocketArray[i] == INVALID_SOCKET) { this->SocketArray[i] = accept(this->AcceptSocket, NULL, NULL); FD_SET(this->SocketArray[i], &(this->fdSet)); std::cout<<"CheckForNewConnection: SocketArray["<<i<<"] mit Verbindung besetzt\n"; freeSocketFound = true; break; } } return freeSocketFound; }Die Receiveroutine empfängt und schließt, wenn nichts mehr empfangen wird von dem socket[x]
void CTCPServer::ReceiveDataOnSocket() { /* Empfängt Daten für jeden gültigen Socket, wenn Receive Null zurückgibt, ist die Verbindung beendet worden. Dann wird der Socket geschloßen und wieder auf INVALID_SOCKET gesetzt. */ for(int i = 0; i < MAX_CLIENTS_TO_CONNECT; i++) { if(this->SocketArray[i] != INVALID_SOCKET) { if(FD_ISSET(this->SocketArray[i], &(this->fdSet))) { unsigned long iRecv = CCreateSocket::ReceivData(this->SocketArray[i]); if(iRecv == 0) { closesocket(this->SocketArray[i]); std::cout<<"ReceiveDataOnSocket: SocketArray["<<i<<"] wurde geschloßen\n"; this->SocketArray[i] = INVALID_SOCKET; std::cout<<"ReceiveDataOnSocket: SocketArray["<<i<<"] wurde auf INVALID_SOCKET gesetzt\n"; FD_CLR(this->SocketArray[i], &(this->fdSet)); std::cout<<"ReceiveDataOnSocket: SocketArray["<<i<<"] wurde mit FD_CLR aus &fdset entfernt\n"; } } } } }Die beiden Routinen werden im loop nacheinander aufgerufen.
erkennt jemand warum dass einmal klappt aber kein weiteresmal?
-
Wenn einer der Sockets im fd_set nach dem select() mal nicht gesetzt ist, setzt Du ihn vor dem nächsten select() mit FD_SET wieder?
-
Wie LordJaxom schon schrieb, liegt Dein Fehler darin, dass Du this->fdSet direkt verwendest. select() verändert das nämlich. Also musst Du vor jedem select() am einfachsten eine "Arbeitskopie" machen. Mit dieser "Arbeitskopie" musst Du dann auch in ReceiveDataOnSocket() arbeiten. Hoffe es wird so klarer.

-
hab gesehen, dass jede zusätzliche socketverbindung immer auf den selben platz in meinem SocketArray[i] gesetzt wird, weil der vorherige wohl mittlerweile invalid geworden ist und deswegen wieder als "freier" platz gehandelt wird...
ich kopiere mir das fdset als in ein fdset2 mit dem ich dann den receive durchführe?
die veränderung die das fd_set macht, kann mir dazu jemand einen link geben? ich verstehe das derzeit nicht so richtig, wieso sich die verändungen so seltsam auswirken. oder einfach ein kleines beispiel

-
fd_set ist doch auch nur ein Bitfeld. Wobei jedes Bit einen Socket (bzw. eine Socket-Nummer) repräsentiert.
Anstatt zu sagen select setzt alle Bits auf deren Sockets etwas passiert ist hilft Dir evtl. folgende Betrachtung:
Du setzt alle Bits in einem fd_set, deren Socket Du beobachten möchtest. Select löscht alle Bits auf deren Sockets nichts passiert ist. Ich denke daraus lässt sich recht einfach schliessen, dass Du vor dem nächsten select erstmal wieder alle Bits setzen musst, die durch select gelöscht wurden (oder Du kopierst Dir den fd_set mit allen gesetzten Bits einmal weg).
-
bei dieser codezeile:
this->SocketArray[i] = accept(this->AcceptSocket, NULL, NULL);muss ich, nachdem ich die verbindung an socketArray[i] angenommen hab, den AcceptSocket wieder neu aufbauen oder kann dieser ohne weiteres so gelassen werden um die nächste verbindung anzunehmen?
-
Bleibt solange, bis du ihn explizit schließt (oder was kaputt geht). Musst also nichts weiter machen, nur den Rückgabewert von accept solltest du noch prüfen, für den Fall dass accept fehlgeschlagen ist.