Threadproblem bei Server-Client-Programm
-
Das heisst, der Kontruktor sollte in der Header von ServerConnection schon definiert werden?
Oder wie hab ich das vorzustellen?
Habe die Templatedefinition aus der thread-Klasse von boost, deshalb weiss ich es nicht besser, habe bisher nicht mit templates aktiv gearbeitet.
(ich schau mal im FAQ)
Ah. Also muss ich entweder direkt im Header definieren oder eine .impl-Datei schreiben, wo die Templates definiert werden...
-
Fabulus schrieb:
Das heisst, der Kontruktor sollte in der Header von ServerConnection schon definiert werden?
Ja.
-
Okay, habe ich gemacht. Das klappt ja soweit schonmal, jetzt kommt aber ein nächstes Kompilierproblem bzgl der threads:
g++ -lboost_thread -o server Socket.cpp network.cpp server_main.cpp ServerSocket.cpp -L/usr/lib64/ /usr/include/boost/thread/detail/thread.hpp: In member function 'void boost::detail::thread_data<F>::run() [with F = void (ServerConnection::*)()]': server_main.cpp:55: instantiated from here /usr/include/boost/thread/detail/thread.hpp:56: error: must use '.*' or '->*' to call pointer-to-member function in '((boost::detail::thread_data<void (ServerConnection::*)()>*)this)->boost::detail::thread_data<void (ServerConnection::*)()>::f (...)' make: *** [server] Error 1Das versteh ich ja noch weniger

-
Zeig mal die server_main.cpp, wie sie jetzt ist.
-
/* server_main.cpp */ /* Die main-Datei des Servers, welche aufgerufen wird */ #include "ServerSocket.h" #include "ClientSocket.h" #include "ServerConnection.h" #include "SocketException.h" #include <string> #include <sstream> #include <iostream> void ServerConnection::calc() { /*std::stringstream ss; std::string data; clientSocket >> data; ss << "Empfangen: " << data << "\n"; clientSocket << ss.str(); */ std::cout << "Ich bin die Methode calc()" << std::endl; } int main ( int argc, char**argv ) { std::cout << "running....\n"; try { // 1. Create the socket // 2. Bind Socket to Port // 3. Set Socket to Listen ServerSocket server ( 30000 ); while ( true ) { ClientSocket clientSock; server.accept ( clientSock ); /* Hier wird die Connection erstellt. Diese gibt die Funktion calc() an * den Thread weiter und den akzeptierten Socket */ ServerConnection sc(clientSock, &ServerConnection::calc); sc.join(); } } catch ( SocketException& e ) { std::cout << "Exception was caught:" << e.description() << "\nExiting.\n"; } return 0; }
-
Verstehe. Du übergibst ihm mit &calc einen Pointer auf eine Memberfunktion. Die kann der Thread natürlich nicht ohne weiteres aufrufen, da er schließlich noch ein konkretes Objekt braucht.
Das musst du entweder mit boost::bind daran binden oder das insgesamt anders lösen.
-
Ah, weil calc() ja keine statische Methode ist, müsste ich quasi die Methode eines Objektes vom Typ ServerConnection angeben?
Das heißt, wenn ich diese Methode statisch mache, würde das vorerst funktionieren.Wie funktioniert das denn mit bind? Auf der Boost-Documentation-Seite finde ich da keine Hilfe zu.
-
Das er hier die Definition einer Template-Memberfunktion in die cpp gepackt hat spielt hier keine Rolle?
-
Habe es schon geändert, gibt jetzt nur noch den Konstruktor in ServerConnection.h, die .cpp-Datei gibt es nicht mehr

-
Fabulus schrieb:
Wie funktioniert das denn mit bind?
So:
http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html#with_member_pointers
-
Blicke ich noch nicht so durch

Mit dem Beispiel aus der Doku wird doch nur die Funktion aufgerufen (So wie es daneben im Kommentar steht)
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).Ich weiß nicht, wie ich den bind-Befehl mit meinem Code kombinieren soll.
Soll ich beim Erstellen der ServerConnection-Instanz das bind() in den Argumentaufruf setzen wie hier:ServerConnection sc(clientSock, bind(&ServerConnection::calc, /* Was soll hier jetzt hin? */)); sc.join();
-
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
