C++ Winsock Server - mehrere Clients handlen



  • Hallo zusammen,

    ich habe folgendes Problem: ich möchte einen Server (der mit winsocks arbeitet)
    so schreiben, dass er mehrere Clients akzeptiert und dann bestimmten
    Clients (per send()) einen Text sendet und ebenso von ausgewählten Clients Daten empfängt.

    Das mit dem akzeptieren der Clients war relativ leicht zu realisieren (multithreading). Allerdings weiß ich nicht wirklich wie ich das mit dem
    Senden anstellen soll. Hat da jmd. vielleicht einen kleinen Hinweis für mich?
    Würde mich über eine Antwort freuen 🙂

    Gruß

    Cyax



  • Cyax schrieb:

    Das mit dem akzeptieren der Clients war relativ leicht zu realisieren (multithreading). Allerdings weiß ich nicht wirklich wie ich das mit dem
    Senden anstellen soll. Hat da jmd. vielleicht einen kleinen Hinweis für mich?
    Würde mich über eine Antwort freuen 🙂

    Das accept gibt dir ein Socket zurück, das für die Verbindung mit genau diesem Client steht. Beim send und recv gibst du mit Socket an mit welchem Client du kommunizieren möchtest.



  • Hm ja, stimmt, aber wenn ich z.B. einen
    SOCKET array nehme geht das nicht.

    SOCKET s[10];
    
    //...
    
    s[x] = accept(...);
    send(s[x], ...);
    // WSAGetLastError() : 10038
    

    Da mache ich irgendwas falsch...
    was brauche ich denn noch alles um die Clients dann
    einzeln anzusteuern?



  • Wenn du in jedem Thread durch accept EIN Socket zurückbekommst, kannst du damit einfach schreiben. Und dann kannst du mehrere Clients durch multithreading gleichzeitig bedienen.



  • Cyax schrieb:

    SOCKET s[10];

    //...


    send(s[x], ...);
    // WSAGetLastError() : 10038
    [/code]

    Da mache ich irgendwas falsch...



  • Bengo schrieb:

    Wenn du in jedem Thread durch accept EIN Socket zurückbekommst, kannst du damit einfach schreiben. Und dann kannst du mehrere Clients durch multithreading gleichzeitig bedienen.

    Naja, so hab ichs ja letztendlich gemacht, allerdings ist mir noch nicht
    ganz klar wie ich dann "mehrere Clients durch multithreading gleichzeitig bedienen" kann...

    Hier mal mein Code für das "akzeptieren" von neuen Clients.

    DWORD WINAPI cmd_handler(LPVOID lpParam)
    {
    	SOCKET active_socket = (SOCKET)lpParam;
    	char recv_buffer[256];
    	std::string sent_data = "msg";
    	int rc;
    
    	for (;;){
    		if (active_socket != INVALID_SOCKET){
    			rc = send(active_socket, sent_data.c_str(), strlen(sent_data.c_str()), 0);
    			if (rc <= 0){
    				std::cout << "Error sending command" << std::endl;
    				closesocket(active_socket);
    				ExitThread(0);
    				return 1;
    			}
    		}
    		else{
    			std::cout << "Client disconnected" << std::endl;
    			closesocket(active_socket);
    			ExitThread(0);
    			return 1;
    		}
    		sent_data.clear();
    	}
    }
    
    //main und anderes Zeug
    SOCKET client;
    //...
    client = accept(acceptSocket, (sockaddr*)&from, &fromlen);
    char *connected_ip = inet_ntoa(from.sin_addr);
    std::cout << "Client " << clientCounter << " connected from " << connected_ip << std::endl;
    CreateThread(NULL, 0, cmd_handler, (LPVOID)client, 0, &thread);
    


  • Cyax schrieb:

    Naja, so hab ichs ja letztendlich gemacht, allerdings ist mir noch nicht
    ganz klar wie ich dann "mehrere Clients durch multithreading gleichzeitig bedienen" kann..

    Das kaufe ich dir nicht ab.

    while((current_socket = accept(main_socket)) !=  INVALID_SOCKET)
    {
            //Du willst vielleicht nicht, dass dir jemand nur Müll sendet und du dann später abbrechen musst,
            //und du daher einen Thread umsonst aufgemacht hast. Deswegen willst du vielleicht noch eine
            //kleine, schnelle Plausibilitätsprüfung machen ...
            if(check_if_alright(current_socket))
            {
                    close(current_socket);
                    continue;
            }
    
            //Dann brauchst du einen Pool für die TIDs, das ist aber auch relativ einfach.
            //Wenn das nicht geklappt hat, kannst du den Socket auch gleich wieder schließen.
            tids[current_tid] = start_thread(current_socket);
            if(!tids[current_tid])
            {
                    close(current_socket);
                    continue;
            }
    
            //Jetzt ist der Thread gestarted - lass ihn machen, er wird von alleine Abräumen. Aber aufpassen,
            //dass der Thread fertig ist, bevor du tids wieder überschreibst. Du musst den Thread ja später
            //noch abräumen.
    
            ++current_tid;
    }
    

    Das Konzept ist ganz einfach, nur die Implementierung ist schwer. Zumindest, wenn du das ordentlich machen willst. Was da noch fehlt, ist das Durchrollen in deinem Threadpoolbuffer, und natürlich das Freigeben. Dafür gibts aber API-Dokus. Die musst du dann nutzen.

    Und jetzt erkläre mal, wie du darauf nicht kommst. Du weißt, was Threads sind, oder? Du weißt, wie die funzen? Wenn nicht - es gibt im Internet tausenundeinen Artikel dazu. Wenn du's weißt - wieso kommst du dann nicht auf diese Lösung? Verstehst du die API-Dokumentationen nicht?



  • Also ok, ich habs jetzt einfach so gelöst, das dem Thread eine
    Struktur übergeben wird, in welcher unter anderem der von accept
    zurückgegebene Socket eingetragen wird und zudem eine einzigartige
    ID des Clients. Dann gibt es noch eine globale Variable über welche
    ich quasi die Clients auswählen kann, da der Thread in einer endlos
    Schleife immer schaut, ob denn seine eigene ID zufällig grad in der
    globalen Variable gespeichert wurde. Sollte dies der Fall sein, so
    öffnet der Thread eine Konsole, um dem ausgewählten Client Befehle
    zu senden.


Anmelden zum Antworten