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 (mitFD_SET
). Dieses Packen ist notwendig, da man mitselect ()
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 vonselect ()
FD_ISSET(sock.Socket, &rd_ready)
wahr ist (prüft, ob auf diesem Socket etwas passiert ist, währendselect ()
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 beicout<<"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?