Sockets - Verbindung Clientseitig beendet, wie verfahren?



  • Moin,

    ich schreibe derzeit an einer Client / Server Anwendung, die mit Sockets verfährt.
    Klappt soweit auch ganz gut, es gibt nur ein Problem. Ich poste zur Verständlichkeit mal meinen Code (Dieser Code wird zur Verwaltung der Clients benutzt, wird als Thread gestartet):

    void *manageUser(void * arg)
    {
        cout<<"Verbunden...\n";
        int socketOfUser=*(int *) arg;
        sockClient sock(0, socketOfUser);
    
        int result;
        string Msg="";
        fd_set rd_ready;
        struct timeval maxwait;
        maxwait.tv_sec = 0; maxwait.tv_usec = 10;
        while(true)
        {
            FD_ZERO(&rd_ready);
            FD_SET(sock.Socket, &rd_ready);
    
            result=select(sock.Socket+1, &rd_ready, NULL, NULL, &maxwait);
            if(result)
            {
                Msg=sock.recvMsg();
                if(Msg=="ping")
                {
                    sock.sendMsg("pong\n");
                    cout<<"Ping erhalten, ponge zurück!\n";
                }
                else if(Msg=="exit")
                {
                    sock.sendMsg("Bye! Feel free to come back!\n");
                    break;
                }
                else
                {
                    cout<<"Unbekannte Nachricht erhalten: "<<Msg<<", schreibe zurück->$ "<<endl;
                    sock.sendMsg("Ich akzeptiere nur Pings, schick mir einen!\n");
                }
            }
        }
        cout<<"User logged out\n";
        sock.closeConnection();
        return arg;
    }
    

    Und dieser Code wird verwendet um die jeweiligen Clients in Threads zu übergeben:

    while(true)
    {
        cout<<"Warte auf Peers...\n";
        int Socket=Streamer.acceptPeerGetSocket();
        cout<<"Signal von Peer empfangen, verbinde...\n";
    
        pthread_t thread;
        int status;
        pthread_create(&thread, NULL, manageUser, &Socket);
    
        pthread_join(thread, (void **) &status);
    }
    

    Das Problem ist nun also dass wenn ein Client das Programm einfach beendet (oder den Prozess abbricht, usw, usw) und nicht vorher "exit" schickt, dass der Server sich dann einfach beendet. Aber warum tut er das? Er dürfte doch aus der While(true) eigentlich nie raus?? Der "result" Integer bleibt dabei übrigens immer auf 0 (bzw. 1 wenn er eine Nachricht erhält) also nie -1 was ja auf einen Fehler hinweisen würde. Stattdessen kommen Nachrichten ohne Inhalt an (also "\n"). Aber nur danach zu prüfen wäre ja nicht zufriedenstellend...

    Wer kann mir helfen?

    Mfg

    Chris

    EDIT: Kann mir zusätzlich nochmal einer erklären warum man bei der 17ten Zeile des ersten Codes Socket+1 nehmen muss? Ich hab das so in meinen Recherchen immer vorgefunden und habs einfach übernommen. Genausowenig ist mir klar was die 14te und 15te Zeile bewirkt.?



  • Wirft sockClient::recvMsg () eine Exception, die du nicht fängst?

    Zu Zeile 14-17: Du packst deinen Socket in ein "FD-Set" (FD steht für File Descriptor, in diesem Fall dein Socket). Zuerst leerst du dafür das Set (mit FD_ZERO ) und packst anschließend deinen Socket rein (mit FD_SET ). Dieses Packen ist notwendig, da man mit select () auch gleichzeitig auf Aktionen von mehreren Sockets warten kann und man alle Sockets, die man "überwachen" will, auf diese Weise der Funktion übergibt. Außerdem solltest du prüfen, ob nach dem Aufruf von select () FD_ISSET(sock.Socket, &rd_ready) wahr ist (prüft, ob auf diesem Socket etwas passiert ist, während select () gewartet hat).

    Mit dem ersten Parameter für select () musst den Socket mit dem höchsten File Descriptor, der im fd_set vorhanden ist, plus 1, angeben (wird intern vom Betriebssystem benötigt).



  • Erstmal danke für die Erklärung, erscheint mir sogar logisch 😃

    recvMsg besteht ausschließlich aus dem normalen recv und einer Umwandlung zum (std::)string.
    Also keine Exception 😃
    sockClient ist nur ne Klasse von mir die ich geschrieben habe ums übersichtlicher zu halten.



  • Setzt die Funktion bei der Umwandlung in std::string denn auch ein String-Termination-Byte (0)?

    char buf [256];
    int rc = recv (Socket, buf, 256, 0);
    buf [rc] = '\0';
    return std::string (buf);
    


  • Der müsste da sein, da ich das charArray in ein stringstream einlese und dieses dann zum string umwandle (mit linestream.str();)
    Aber der normale Nachrichtenversand funktioniert ja... Der Fehler tritt wirklich nur auf wenn der Client einfach abhaut ohne 'Tschüss' zu sagen 😛
    Ich könnte mir vorstellen dass der Fehler bei

    cout<<"Unbekannte Nachricht erhalten: "<<Msg<<", schreibe zurück->$ "<<endl;
    sock.sendMsg("Ich akzeptiere nur Pings, schick mir einen!\n");
    

    liegt. Msg ist ja wie oben erwähnt "". Könnte es sein dass er bei send(); (auch hier nur eine Methode meiner Klasse, der ich einen string geben kann) dann versucht an einen Client zu senden obwohl der garnicht mehr da ist? Aber dann müsste es doch eig. nur einen negativen Rückgabewert geben(?), und keinen Absturz des Programms?



  • Chris-S schrieb:

    Der müsste da sein, da ich das charArray in ein stringstream einlese und dieses dann zum string umwandle (mit linestream.str();)

    Hat doch damit nix zu tun, woher soll der String-Stream wissen, dass dein char-Array zu Ende ist?


Anmelden zum Antworten