Threads in bestehendes Programm einbinden?
-
Hallo.
Es geht um folgendes. Ich möchte ein bestehendes Linux-Programm so umschreiben, dass es sowohl unter Linux als auch Windows läuft.
Von der Funktionalität her sind es zwei einfache unidirektionale TCP/IP Verbindungen (je eine Verbindung für senden/empfangen) welche je nach Wunsch als Client oder Server laufen sollen.Das Umschreiben der Sockets war relativ problemlos, jedoch bin ich am Verzweifeln was das Threading angeht, in welchem auf ankommende Daten gewartet wird.
In Linux wurde pthread verwendet, welches ich aber unter Windows nicht verwenden möchte.
Programmaufbau ist in etwa so:
_____________main.cpp________________
| |
send.cpp receive.cpp
-socket init - socket init
- stdio --> senden - im Thread auf daten wartenProblem is, dass die Funktion die im Thread laufen soll relativ groß is.
Hab versucht mittels CreateThread einzubinden, aber da wurd ich nur ovn Fehlermeldungen erschlagen.So wie ich das verstanden habe, müssen sämtliche Ein und Ausgabewerte der Funktion noch für den Thread umgewandelt werden?! Falsch?
Hätte evtl. jemand ein simples Beispiel wie man eine nicht in der main befindliche Funktion in sonen Thread packt oder gar einen anderen Lösungsweg?
Vielen Dank im Voraus.
-
Du könntest boost verwenden, da gibts eine Thread Library die für Linux und Windows geht und ein einheitliches Interface bietet (auch für Sockets).
-
So. Habs jetz geschafft den Thread mit "CreateThread" zu erzeugen.
Wenn beide Verbindungen in meinem Programm als Client fungieren klappt alles wunderbar.
Stell ich jedoch beide auf "Server" um, scheint was im argen zu sein.Wenn sich accept im Thread befindet blockiert accept nich mehr und läuft einfach durch. Klar, dass das schief geht.
Mit meinem besten Freund google hab ich herausgefunden, dass dies der Fall sein kann wenn man Socket nicht richtig in den Thread übergibt. http://www.computerbase.de/forum/showthread.php?t=724387Aber ich erstelle den socket ja erst im Thread, also müssts doch eigentlich passen? Oder geht das nich, Socket im Thread erstellen?
Grüße und abermals danke im Voraus,
der Typ der jetz schlafen geht.
-
Oder geht das nich, Socket im Thread erstellen?
Doch das geht. Ev. ist etwas anderes falsch. Zeig doch mal den Code.
-
Server Init:
bool ReceiveSeite::ServerInit( int port, const char* ip ) { bool result = false; #ifndef __linux__ WSADATA w; if(int rc = WSAStartup(MAKEWORD(2,2), &w) != 0) { fprintf(stderr,"Winsock 2 konnte nicht gestartet werden! Error #%d\n",rc); return 1; } #endif int portno = GlobalConst::initializeIntegerVariables; int on = 1; struct sockaddr_in serverAddress = { 0, 0, { 0 }, "" }; if( port < 0 || port > GlobalConst::maxPortRange ) { std::cerr << "Port is out of range (ReceiveSeite - Server)" << std::endl; exit(1); } portno = port; m_sockFileDescriptor = socket(AF_INET, SOCK_STREAM, 0); // kann ?bernommen werden // if( m_sockFileDescriptor < 0 ) { fprintf(stderr, "Error opening socket IP: %s / Port: %i in Seite Server, reason: Opening.\n", ip, port); exit(0); } // needed to free bind right after socket is not used anymore if( setsockopt(m_sockFileDescriptor, SOL_SOCKET, SO_REUSEADDR, (char*) &on, sizeof( on )) < 0 ) { std::cerr << "could not setup socket to free bind if socket is not used anymore" << std::endl; } if( NULL != memset((char *) &serverAddress, 0, sizeof( serverAddress )) ) { result = true; } else { std::cerr << "Error on memset." << std::endl; result = false; } serverAddress.sin_family = AF_INET; if( inet_addr(ip) == INADDR_NONE ) { fprintf(stderr, "Invalid command line argument provided\nParameter#5: %s\n", ip); exit(0); } serverAddress.sin_addr.s_addr = inet_addr(ip); serverAddress.sin_port = htons(portno); if( bind(m_sockFileDescriptor, (struct sockaddr *) &serverAddress, sizeof( serverAddress )) < 0 ) { fprintf(stderr, "Error opening socket IP: %s / Port: %i in Seite Server, reason: Binding\n", ip, port); exit(0); } int rc = listen(m_sockFileDescriptor, 1); //, 1 if( rc == -1 ) { std::cout << "Error on listen!" << std::endl; exit(0); } m_serverFlagReceive = true; setServerState(); return result; }
Thread: Auf Verbindung warten und Daten empfangen
bool ReceiveRole::run() { bool result = false; bool resultAlreadySetFalse = false; #ifdef __linux__ socklen_t clientLength = GlobalConst::initializeClientLength; #elif defined _WIN32 || defined _WIN64 //int socklen_t; int clientLength = GlobalConst::initializeClientLength; #endif char buffer[GlobalConst::maxMessageLength]; struct sockaddr_in clientAddress = { 0, 0, { 0 }, "" }; int m_checkRecv = GlobalConst::initializeIntegerVariables; if( mServerState == true ) { // We are running the server side specific code std::cerr << "waiting for connection (receive role - server)" << std::endl; long rc; if( ( m_sockFileDescriptor = accept(m_sockFileDescriptor, (struct sockaddr *) &clientAddress, &clientLength) ) == -1 ) { std::cout << "ERROR" << std::endl; mThreadRunning = false; } else { m_sockFileDescriptor = 1; std::cerr << "got connection (receive role - server)" << std::endl; while( mThreadRunning ) { if( NULL != memset(buffer, 0, GlobalConst::maxMessageLength) ) { result = true; } else { std::cerr << "Error on memset." << std::endl; result = false; resultAlreadySetFalse = true; } m_checkRecv = recv(m_newSockFileDescriptor, buffer, sizeof( buffer ), 0); if( m_checkRecv == -1 ) { std::cerr << "ERROR with recv" << std::endl; exit(1); } else if( m_checkRecv == 0 ) { std::cerr << "client disconnected!" << std::endl; if( 0 != raise(15) ) { if( resultAlreadySetFalse == false ) { result = true; } } else { std::cerr << "Error on raise funtion!" << std::endl; result = false; resultAlreadySetFalse = true; } } buffer[m_checkRecv] = '\0'; std::cout << "receive(" << m_checkRecv << "," << buffer << ")" << std::endl; if( false == m_log->writeLogfile(buffer, false) ) { std::cerr << "Error in write to log file, reason: see error message above" << std::endl; exit(1); } } } } else { // We are the client, so use the specific code while( mThreadRunning ) { if( NULL != memset(buffer, 0, GlobalConst::maxMessageLength) ) { if( resultAlreadySetFalse == false ) { result = true; } } else { std::cerr << "Error on memset." << std::endl; result = false; resultAlreadySetFalse = true; } m_checkRecv = recv(m_sockFileDescriptor, buffer, sizeof( buffer ), 0); if( m_checkRecv == 0 ) { std::cerr << "server disconnected!" << std::endl; if( 0 != raise(15) ) { if( resultAlreadySetFalse == false ) { result = true; } } else { std::cerr << "Error on raise funtion!" << std::endl; result = false; resultAlreadySetFalse = true; } } buffer[m_checkRecv] = '\0'; std::cout << "receive(" << m_checkRecv << "," << buffer << ")" << std::endl; if( false == m_log->writeLogfile(buffer, false) ) { std::cerr << "Error in write to log file, reason: see error message above" << std::endl; exit(1); } } } /** * Clean up newsocketfd */ std::cerr << "quitted thread?" << std::endl; return result; }
TY in advance.
-
Ich würde noch WSAGetLastError(..) abfragen, wenn accept(..) -1 zuurückliefert.
So hast Du noch etwas mehr Informationen welche Aufschluss über die Ursache geben könnten.[EDIT]
MSDN zu accept(..): http://msdn.microsoft.com/en-us/library/ms737526.aspx
MSDN zu WSAGetLastError(..): http://msdn.microsoft.com/en-us/library/ms741580.aspx
-
Hm. Daruf hätt ich auch kommen können! xD
Jedenfalls spuckt er "returns error 10014 " aus. Bad Address.
Sieht so aus, als würde er den außerhalb vom Thread erstellten Socket nich finden.Lässt sich das irgendwie beheben, ohne die komplette Socker-Routine in den Thread zu packen?
-
Ich denke, deine Probleme haben weniger mit Threads zu tun, als vielmehr einfach mit der Socket API.
http://msdn.microsoft.com/en-us/library/ms740668(v=vs.85).aspx#WSAEFAULT
// Dein Code struct sockaddr_in clientAddress = { 0, 0, { 0 }, "" }; // Korrigierter Code struct sockaddr_in clientAddress = { };
-
Oha. Danke. Außerhalb des Threads hats halt funktioniert. Aber ich werd dem Nachgehn. Merci.
-
Außerhalb des Threads hats halt funktioniert.
Das war Zufall...