Multiple Clients



  • Hallo,

    ich habe ein TCP-Server der mehrere Clients akzeptiert. Durch die WINAPI select() funktion blockieren die Calls(accept & recv) nicht mehr. Es funktioniert ohne Fehler, jedoch verhält er sich komisch:

    Wenn die Clients die er akzeptieren kann zb. maximal 2 sind, und der Erste sich verbindet und etwas schickt(string) kommt die Nachricht beim Server nicht an-> Bis ich den 2 Client starte. In dem Moment erhält er die Nachrichten. Und weiter können die beiden Clients nur noch abwechselnd Nachrichten schicken. Also erst 1, dann 2. Wenn zb. 1 zwei Strings schickt kommt der zweite nicht an. Das gleiche passiert auch, wenn ich die Anzahl der Clients die akzeptiert werden können erhöhe.

    Ich habe wohl irgendwo einen Logikfehler, das Problem ist ich komme nicht drauf. Ich hoffe Ihr könnt helfen.

    Hier der entsprechende Ausschnitt:

    int main()
    {
    	timeval timeout;
    	timeout.tv_sec = 0;
    	timeout.tv_usec = 5;
    
    	const int N=2;
    	SOCKET clients[N];
    	FD_SET set;
    
                            [...]
    
    //==================FD_SET=====================//
    	//--- initialisieren ---
    	for(int i=0;i<N;i++){
    		clients[i] = -1;
    	}
    
    	//--- FD_SET Endlosschleife ---
    
    	while(1){
    
    		//--- set muss immer erneut geleert werden, da
    		// select() das set manipuliert
    		FD_ZERO(&set);
    		FD_SET(server,&set);
    
    		//--- gültige Clients zum set hinzufügen
    		for(int i=0;i<N;i++){
    			if(clients[i] != -1){
    				FD_SET(clients[i],&set);
    			}
    		}
    
    		rc = select(-1,&set,NULL,NULL,&timeout);
    		if(rc == SOCKET_ERROR){
    			cout << "select()_Fehler " << GetLastError() << endl;
    			closesocket(server);
    			WSACleanup();
    			getchar();
    			return 1;
    		}
    
    		if(FD_ISSET(server,&set)){
    			for(int i=0;i<N;i++){
    				if(clients[i] == -1){
    					//--- Verbindungen akzeptieren ---
    					//SOCKET msocket;
    					SOCKADDR_IN quelle;
    					int quelleL = sizeof(quelle);
    
    					clients[i] = accept(server,(SOCKADDR *)&quelle,&quelleL);
    
    					if(rc == INVALID_SOCKET){
    						cout << "accept() Fehler " << GetLastError() << endl;
    						WSACleanup();
    						closesocket(server);
    						closesocket(clients[i]);
    						getchar();
    						return 1;
    					}
    
    					cout << "Verbindung hergestellt! " << endl << "ClientIP " << inet_ntoa(quelle.sin_addr) 
    						<< " : " << ntohs(quelle.sin_port) << endl;
    					//--- ENDE ---
    				}
    			}
    		}
    		//--- Clientsocket zum datenempfang suchen ---
    		for(int i=0;i<N;i++){
    			if(clients[i] == -1){
    				continue;
    			}
    			//--- Empfangen ---
    			char buffer[100];
    			rc = recv(clients[i],buffer,strlen(buffer),0);
    
    			if(FD_ISSET(clients[i],&set)){
    				if(rc == 0 || rc == SOCKET_ERROR){
    					cout << "Client hat verbindung geschlossen" << endl;
    					closesocket(clients[i]);
    					clients[i] = -1;
    				}
    			}
    			else{
    				//=== Daten empfangen & senden ===
    				if(rc > 0){
    					buffer[rc] = 0;
    					cout << rc << " bytes empfangen" << endl;
    					cout << "Nachricht: " << buffer << endl;
    				}
    				if(buffer[0] == '#'){
    					cout << "'quit' erhalten, beende Server..." << endl;
    					WSACleanup();
    					closesocket(server);
    					closesocket(clients[i]);
    					getchar();
    					return 0;
    				}
    			}
    		}
    	}
    
    	//======== Ende ==================
    	cout << "Beende Programm..." << endl;
    	//--- Aufräumen ---
    	getchar();
    	WSACleanup();
    	return 0;
    
    }
    


  • Zwei Dinge.

    Pack bitte diesen Teil mit in die Schleife:

    timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 5;
    

    Denn select manipuliert timeout möglicherweise.

    Und dann solltest du recv nur dann aufrufen, wenn das FD_ISSET true ist.

    if (FD_ISSET(...))
    {
     int rc = recv(...);
    
     if (rc <= 0)
     {
      // Error oder geschlossen
     } 
     else
     {
      // Kam was zurück...
     }
    }
    


  • ich habe das recv() nach die FD_ISSET() prüfung gestellt. Jetzt empfängt er erst Nachrichten wenn beide Clients verbunden sind. Wenn nur ein Client verbunden ist und er Daten verschickt, kommen die beim Server erst an wenn sich ein zweiter verbindet. Jedoch kann jetzt jeder Client etwas verschicken, was dann auch ankommt, jedoch nur wenn, wie gesagt beide verbunden sind. Wenn ein Client beendet, dann gibt der Server auch keine Nachrichten mehr aus.

    Außerdem empfängt der Server nur noch einzelne Zeichen, Bsp. wenn "Hallo" geschickt wird empfängt er "H" dann "o" usw.

    Auch wenn ich die timeval strukturen aus dem Code nehme ändert sich nichts.

    int main()
    {
    
        char buffer[100];
    
        const int N=2;
        SOCKET clients[N];
        FD_SET set;
    
                            [...]
    
    //==================FD_SET=====================//
        //--- initialisieren ---
        for(int i=0;i<N;i++){
            clients[i] = -1;
        }
    
        //--- FD_SET Endlosschleife ---
    
        while(1){
    
            timeval timeout;
            timeout.tv_sec = 0;
            timeout.tv_usec = 5;
    
            //--- set muss immer erneut geleert werden, da
            // select() das set manipuliert
            FD_ZERO(&set);
            FD_SET(server,&set);
    
            //--- gültige Clients zum set hinzufügen
            for(int i=0;i<N;i++){
                if(clients[i] != -1){
                    FD_SET(clients[i],&set);
                }
            }
    
            rc = select(-1,&set,NULL,NULL,&timeout);
            if(rc == SOCKET_ERROR){
                cout << "select()_Fehler " << GetLastError() << endl;
                closesocket(server);
                WSACleanup();
                getchar();
                return 1;
            }
    
            if(FD_ISSET(server,&set)){
                for(int i=0;i<N;i++){
                    if(clients[i] == -1){
                        //--- Verbindungen akzeptieren ---
                        //SOCKET msocket;
                        SOCKADDR_IN quelle;
                        int quelleL = sizeof(quelle);
    
                        clients[i] = accept(server,(SOCKADDR *)&quelle,&quelleL);
    
                        if(rc == INVALID_SOCKET){
                            cout << "accept() Fehler " << GetLastError() << endl;
                            WSACleanup();
                            closesocket(server);
                            closesocket(clients[i]);
                            getchar();
                            return 1;
                        }
    
                        cout << "Verbindung hergestellt! " << endl << "ClientIP " << inet_ntoa(quelle.sin_addr)
                            << " : " << ntohs(quelle.sin_port) << endl;
                        //--- ENDE ---
                    }
                }
            }
            //--- Clientsocket zum datenempfang suchen ---
            for(int i=0;i<N;i++){
                if(clients[i] == -1){
                    continue;
                }
                //--- Empfangen ---
    
                if(FD_ISSET(clients[i],&set)){
                    rc = recv(clients[i],buffer,strlen(buffer),0);
                    if(rc == 0 || rc == SOCKET_ERROR){
                        cout << "Client hat verbindung geschlossen" << endl;
                        closesocket(clients[i]);
                        clients[i] = -1;
                    }
                }
                else{
                    //=== Daten empfangen & senden ===
                    if(rc > 0){
                        buffer[rc] = 0;
                        cout << rc << " bytes empfangen" << endl;
                        cout << "Nachricht: " << buffer << endl;
                    }
                    if(buffer[0] == '#'){
                        cout << "'quit' erhalten, beende Server..." << endl;
                        WSACleanup();
                        closesocket(server);
                        closesocket(clients[i]);
                        getchar();
                        return 0;
                    }
                }
            }
        }
    
        //======== Ende ==================
        cout << "Beende Programm..." << endl;
        //--- Aufräumen ---
        getchar();
        WSACleanup();
        return 0;
    
    }
    

Anmelden zum Antworten