Threadproblem bei Server-Client-Programm


  • Mod

    Fabulus schrieb:

    Aber ich habe doch gar keine Argumente, die an calc übergeben werden müssen.
    Und ich habe auch kein Objekt, welches ich angeben könnte (im Beispiel ist es das x).

    😕 Wieso machst du es dann überhaupt so kompliziert, wenn du das gar nicht möchtest? Überdenke dein Design!



  • Mein Plan ist folgender gewesen:

    Der Server ist die ganze Zeit online und akzeptiert in einer while-true-Schleife alle eingehenden Verbindungen. Damit aber gleichzeitig mehrere Clients sich anmelden können, soll eine neue ServerConnection erstellt werden, welche quasi ein Thread ist, in dem dann die Berechnung bzw. die Stringumformungen gemacht werden.
    Als Argumente für die Serverconnection gebe ich den ClientSocket an und die Methode, die im Thread ausgeführt werden soll.

    Ist das Prinzip verständlich?

    Es soll quasi bei einer neuen Client-Verbindung ein neuer Thread gestartet werden.

    Edit:
    Wenn ich eine globale Methode erstelle, klappt dies soweit, habe dann aber keinen Zugriff mehr auf den clientSocket, den ich bei der ServerConnection erstelle, deshalb würde ich lieber ne Methode von ServerConnection übergeben.



  • Wenn du die calc-Methode von ServerConnection verwenden willst, dann brauchst du sie doch eigentlich nicht im Konstruktor von ServerConnection zu übergeben. Es würde doch reichen sie in der Initialisierungsliste des Konstruktors an thread zu übergeben. Irgendwie so

    ServerConnection(const ClientSocket& csocket)
    : boost::thread(boost::bind(&ServerConnection::calc, this)), clientSocket(csocket)  { }
    


  • Ah, wunderbar, das funktioniert! Hätte ich auch selber drauf kommen können. Dann spar ich mir auch das Template 🙂

    Danke sehr 🙂

    Wenn es noch was bzgl. dieses Themas gibt, melde ich mich wieder.

    EDIT:

    Ich möchte jetzt zusätzlich noch eine Clientconnection erstellen. Eine Instanz dieser wird zu Beginn des Clients erstellt und der Thread gestartet. Das einzige, was die Methode, die der Thread aufruft, macht, ist in einer Endlosschleife Nachrichten entgegenzunehmen und auszugeben.

    Das ganze wollte ich jetzt folgendermaßen lösen:

    // client_main.cpp
    #include "ClientSocket.h"
    #include "SocketException.h"
    #include "ClientConnection.h"
    #include <iostream>
    #include <string>
    
    int main ( int argc, char** argv )
    {
    	try
    	{
    
    		ClientSocket client_socket ( "ikp696", 30000 );
    
    		std::string reply;
    		std::string entry;
    		std::string exitmsg="exit";
    
    		ClientConnection cc(client_socket);
    
    		cc.join();
    
                    std::cout << "Test";
    
    		while(true) {
    
    			std::cout << "Enter message: ";
    			getline(std::cin, entry);
    
    			try
    			{
    				// Sende Nachricht an den Sever
    				client_socket << entry;
    
    				if(entry == exitmsg) {
    					client_socket.close();
    					break;
    				}
    			}
    			catch ( SocketException& ) {
    				std::cout << "Socket Exception!";
    			}
    		}
    
    	}
    	catch ( SocketException& e )
    	{
    		std::cout << "Exception was caught:" << e.description() << "\n";
    	}
    
    	return 0;
    }
    
    #ifndef CLIENTCONNECTION_H_
    #define CLIENTCONNECTION_H_
    
    #include <boost/thread/thread.hpp>
    #include <boost/bind.hpp>
    #include "ClientSocket.h"
    
    class ClientConnection : public boost::thread {
    
    public:
    
    	ClientConnection(const ClientSocket& csocket)
    	: boost::thread(boost::bind(&ClientConnection::Run, this)), clientSocket(csocket)  { }
    
    	virtual ~ClientConnection() { }
    
    	void Run();
    
    private:
    	ClientSocket clientSocket;
    
    };
    
    #endif /* CLIENTCONNECTION_H_ */
    
    //ClientConnection.cpp
    #include "ClientConnection.h"
    #include <string>
    
    void ClientConnection::Run() {
    
    		// Empfange Daten vom Server und speichere sie in reply
    		std::string reply="";
    		clientSocket >> reply;
    
    		std::cout << reply << "\"\n";;
    }
    

    Jetzt hab ich das Problem, dass in der Client_main-Datei die Nachricht "Test" nicht ausgegeben wird, weil anscheinend der Thread blockiert oder so.

    Sinn und Zweck der ganzen Sache ist, dass ich gleichzeitig Nachrichten senden und empfangen kann. In Java habe ich es genau so hinbekommen, nur in C++ noch nicht. Kann da jemand noch mal schauen?



  • Indem du auf einem Thread die join - Methode aufrufst, wartest du auf Beendigung des Threads. Wenn der Thread nicht beendet wird, passiert also auch nichts.



  • Und wie ist es möglich, dass ein Thread wirklich _parallel_ läuft`?



  • Dein Thread läuft doch parallel, du darfst halt nur nicht auf seine Beendigung warten - oder eben an anderer Stelle.



  • Gibt es denn Methoden, die den Thread starten und nicht warten, bis dieser zu Ende gelaufen ist, sondern dass Programm weiterläuft und der Thread im Hintergrund auch?

    Irgendwie verstehe ich den Sinn dahinter nicht. Ein Thread ist doch gerade dazu da, dass mehrere Dinge gleichzeitig laufen. Dann ist es doch Schwachsinn, dass erst gewartet werden muss, bis der Thread durchgelaufen ist und dann erst weiter gemacht wird 😕



  • Ich glaube wir beide reden aneinander vorbei. Lass doch einfach das join weg 😉



  • Achso, das bedeutet, ein Thread läuft automatisch, ohne erst den thread wie in Java zu starten?

    Habe dennoch ein weiteres Problem:
    Ich kann jetzt eine Nachricht eingeben, aber keine weitere.
    Die Ausgabe ist folgende (bei der Ausführung des Clients)

    Enter message: Testnachricht
    Enter message: We received this response from the server:
    "Empfangen: Testnachricht"
    terminate called after throwing an instance of 'SocketException'
    Aborted
    

    Dabei schließe ich doch die Verbindung nicht, oder?

    EDIT: Ich habe herausgefunden, das Problem liegt an der Schleife im Thread der Clientconnection. Es wird wieder versucht, etwas zu empfangen, aber dies funktioniert nicht. Dabei soll doch nur empfangen werden, wenn etwas geschickt wurde..



  • Ein Thread wird im Kontruktor gestartet, ja. RAII eben.



  • Verstehe 🙂

    Kann denn irgendwie diese Exception verhindert werden?
    Die wird ja durch den >> Operator ausgerufen, welcher so aussah:

    const ClientSocket& ClientSocket::operator >> ( std::string& s ) const
    {
      if ( ! Socket::recv ( s ) )
        {
          throw SocketException ( "Could not read from socket." );
        }
    
      return *this;
    }
    

    Übergebe ich einen falschen String oder warum kommt die Fehlermeldung?



  • Schau dir das Verhalten doch mal im Debugger an - aber ich würde vermuten, der Socket ist nicht initialisiert, oder er liefert tatsächlich gerade keine Daten.

    PS: Ich würde dort eher einen leeren String zurückgeben, wenn das Problem tatsächlich nur in "keine Daten vorhanden" besteht.



  • Hallo, da bin ich wieder.

    Ich habe leider noch nicht wirklich aktiv mit dem Debugger gearbeitet (was wohl spätestens jetzt der Zeitpunkt wäre, es zu lernen).
    Da habe ich aber noch Probleme:
    Ich benutze das Eclipse IDE für C/C++ Version Helios Release 2

    Ich habe mir eine eigene make-Datei geschrieben, da die Quelldateien in verschiedenen Verzeichnissen liegen.
    Wird beim kompilieren jetzt meine make-Datei benutzt oder eine von Eclipse?

    Wenn ich per Shell make aufrufe, funktioniert das Kompilieren, bei Eclipse kommt jedoch der Error, dass ich zwei main-Funktionen habe (einmal client und einmal den server), wobei ich in der make-Datei es so eingestellt habe, dass nur der server kompiliert werden soll.
    Bevor ich den Debugger nutzen kann, sollte dies doch funktionieren...



  • Ok, konnte das make-File jetzt einbinden und versuche den Debugger zu starten.
    Setze einen Breakpoint in die Run()-Methode der ClientConnection, doch es kommt ein Fehler, mit dem ich nichts anfangen kann:

    Der Debug-Modus aktiviert, aber dann kommt eine Meldung:

    No source available for "main() at 0x4049c2"
    

    Was bedeutet das?



    1. Du hast die Sourcefile geändert, seitdem du das Programm mit Debuginformationen übersetzt hast.
    2. Du hast die main() nicht mit Debuginformationen übersetzt.
    3. Du hast irgendein Framework, und die main() befindet sich garnicht in deinem Code.


  • Mal ne kleine Zwischenfrage - kann Boost kein select() 😕



  • cooky451 schrieb:

    Mal ne kleine Zwischenfrage - kann Boost kein select() 😕

    Google kennst du?
    boost::asio::async_* aufrufen.



  • Entschuldige, dass ich mich jetzt erst wieder melde, war eine Woche nicht da.

    pumuckl schrieb:

    1. Du hast die Sourcefile geändert, seitdem du das Programm mit Debuginformationen übersetzt hast.
    2. Du hast die main() nicht mit Debuginformationen übersetzt.
    3. Du hast irgendein Framework, und die main() befindet sich garnicht in deinem Code.

    Wenn ich auf den Knopf "Debug client" drücke, wird das Makefile erneut ausgeführt und die Dateien mit den Breakpoints (ich hoffe doch, du meinst dies mit Debuginformationen) kompiliert, somit kann ich also den Sourcecode nicht nach Kompilierung ändern.

    Und ob ich ein Framework benutze... ich denke nicht, jedenfalls nicht bewusst, da ich nicht genau weiß, was das ist.

    Edit:
    Im Compiler wird jetzt genau die Zeile, die ich als Breakpoint-Markierung gesetzt habe, als Fehler angezeigt.
    Der Fehler ist:

    Multiple markers at this line
    	- Breakpoint attribute problem: installation 
    	 failed
    	- Line breakpoint: ClientConnection.cpp [line: 
    	 17]
    


  • Probier mal alle Breakpoints zu löschen (idealerweise über eine "Lösche alle Breakpoints" Funktion der IDE), und dann neu zu setzen.


Anmelden zum Antworten