CreateThread - keine Memberfunktion erlaubt ?
-
Iteratoren haben den Vorteil, daß du damit auf beliebigen Datenstrukturen arbeiten kannst - der Zugriff auf eine verkettete Liste (std::list<>) funktioniert genauso wie auf ein dynamisches Array (std::vector<>) oder einen Binärbaum (std::set<>/std::map<>). Mit dem gefundenen Iterator kannst du jetzt weiterarbeiten wie mit einem Zeiger - du dereferenzierst ihn, um an die dahinterstehenden Daten zu gelangen
Wenn du den Index des gefundenen Elements heranwillst, kannst du std::distance() verwenden (für vector<> geht auch die Iterator-Differenz):
std::vector < std::string >::iterator pos; pos = find ( clientNames.begin() , clientNames.end() , clientName ); if ( pos != clientNames.end() ) { int index = std::distance(clientNames.begin(), pos); // oder index = pos-clientNames.begin(); } else { // do it not }PS: Aber ich würde im Ernstfall keine parallelen Arrays verwenden, sondern alle Informationen zu einem Client in eine Struktur zusammenfassen und dann einen
std::vector<ClientData>verwenden.
-
Achso, das ist natürlich praktisch, danke !
Noch eine Frage : Was passiert in dem Fall, wenn das gesuchte Element an der letzten Stelle ist ? Würde das dann nicht fehlschlagen. Denn eig. ist die bedingung if ( pos != clientNames.end() ) nicht erfüllt, aber das Element wurde trotzdem gefunden.
Zu dem gesamt-struct thema : Hmm, wäre das denn besser ? Dann müsste ich immer ewig oft den '.' operator benutzten a la ClientStruct.clientList.ClientNames[index].c_str(); Wie das aussieht

-
Hmmmm schrieb:
Noch eine Frage : Was passiert in dem Fall, wenn das gesuchte Element an der letzten Stelle ist ? Würde das dann nicht fehlschlagen. Denn eig. ist die bedingung if ( pos != clientNames.end() ) nicht erfüllt, aber das Element wurde trotzdem gefunden.
clientNames.end() zeigt nicht auf das letzte Element deiner Liste, sondern hinter das letzte Element.
Zu dem gesamt-struct thema : Hmm, wäre das denn besser ? Dann müsste ich immer ewig oft den '.' operator benutzten a la ClientStruct.clientList.ClientNames[index].c_str(); Wie das aussieht

Viel länger als mit den parallelen Arrays wird der Code dadurch nicht, eher im Gegenteil. Vergleich mal folgendes:
pos = find(ClientNames.begin(),clientNames.end(),name); if(pos!=ClientNames.end()) { int index = distance(clientNames.begin(),pos); return ClientIPs[index]; } // vs. pos = find_if(Clients.begin(),Clients.end(),compare_name(name)); if(pos!=Clients.end()) { return pos->IP; }(außerdem mußt du nicht bei jedem Login und Logout darauf achten, daß die wirklich alle Client-Daten-Arrays synchron zueinander änderst)
-
Ja okay, das stimmt wohl schon, aber ich denke darum kümmere ich mich zum Schluss nochmal.
Momentan habe ich mal wieder ein Problem, seufz. Beschreibung : Ich schicke an einen neu gejointen Client alle Client-Namen. Das Problem : Er bekommt die namen als EINEN string anstatt als mehrere einzelne. Trotz Sleep()-call zwischen den send's !
Code, Clientside
... else if ( buf[0] == '1' ) { char temp[9]; // Hier bekomme ich die Zahl gesendet, wobei ich die vorangehende 1 ignorieren muss. Siehe server-code for ( int k = 0; k < strlen(buf) - 1; k++ ) { temp[k] = buf[k+1]; } temp[strlen(buf) -1 ] = 0; MessageBox( NULL, temp , "Temp is ", MB_OK); // Check ob die Zahl richtig konvertiert wurde, positiv int count = atoi( temp ); for ( unsigned int k = 0; k < count ; k ++ ) { char temp2[200]; rc = recv ( gui.getConnecterClass().getSocket(), temp2 , sizeof(temp2) , 0 ); temp2[rc] = 0; MessageBox( NULL , temp2 , "temp 2 is : " , MB_OK ); // Hier wird das Problem immer klar : Die namen sind als ein String angekommen gui.addClient( temp2 ); } } ...Code, Serverside
... if(buf[0] == '0' ) { // 0 an erster Stelle = neuer Client for ( int count = 0; count < strlen(buf) - 1 ; count ++ ) { // Den struct mit dem Namen füllen. Die message sieht also so aus : clients[i].name[count] = buf[count+1]; // "0NameDesClients". Ist auch alles richtig, hab ich geprüft } clients[i].name[strlen(buf) -1 ] = 0; for ( int j = 0; j < MAX_CLIENTS ; j++ ) { // Den Namen an alle anderen Clients weitergeben, wieder steht 0 für neuer Client if ( clients[j].client != INVALID_SOCKET && j != i ) { // Ist auch alles richtig, der Name des Clients wird bei den anderen richtig char temp[250] = "0"; // hinzugefügt strcat(temp,clients[i].name); send( clients[j].client, temp, strlen(temp) , 0 ); } } if ( clientNames.size() > 0 ) { // Ein std::vector < std::string > char temp[10] = "1"; // 1 steht für : "Ich sende jetzt ein Zahl und soft must du loopen, um alle Namen zu empfangen char temp2[9]; itoa( clientNames.size() , temp2 , 10 ); strcat ( temp , temp2 ); cout << temp << endl; // Zahl wird richtig konvertiert send ( clients[i].client , temp, strlen(temp) , 0 ); Sleep(100); // Der genannte Sleep() da sonst zu schnell hintereinander gesendet wird und der String als einer ankommt for ( unsigned int y = 0; y < clientNames.size(); y++ ) { send ( clients[i].client , clientNames[y].c_str() , strlen(clientNames[y].c_str()), 0 ) ; Sleep(500); // Noch ein sleep, damit die Namen auch nicht als einer ankommen. Übertrieben lang ja, ich wollte nur sehen obs hilft } // Tut es aber nicht, der String kommt als einer an -.- } cout << "Clients[i].name : " << clients[i].name << endl; // Nochmal ein Check ob der Name richtig bestimmt ist, ist er auch clientNames.push_back( clients[i].name ) ; // Namen zu der Namens-Liste hinzufügen } ...Jetzt mal ein Beispiel, damit das Problem klar wird :
Client 1 connected mit Name " Let's ". Server nimmt ihn an, speichert den Namen fertig.
Client 2 connected mit dem Namen "test ". Server nimmt ihn an, schickt an Client 1 "0test " woraufhin dieser "test " auf seine Client-List setzt.
Weiter schickt der Server "11" ( Messagebox1 : "1" ) an Client 2 , woraufhin dieser 1 mal loopt und dabei " Let's " ( MessageBox2 : " Let's " ) auf seine Client-List setzt.
Client 3 connected mit dem Namen "this !". Server schickt an Client 1 und 2 "0this !", woraufhin beide erfolgreich "this !" auf ihre Client-List setzen.
Weiter schickt der Server an Client 3 "12" ( MessageBox1 : 2 ) woraufhin folgendes passiert : MessageBox2 ist : "Let's test" beim ersten mal loopen des Clients. Daraufhin callt Client 3 im 2. loop-Durchgang nochmal recv(), da der Server aber schon alles gesendet hat, blockiert recv() die Message-Schleife und Client 3 hängt sich auf.
-
Da solltest du ein Kennzeichen festlegen, wo ein String zu Ende ist und der nächste anfaängt (entweder du überträgst vorher die Stringlänge oder du sendest den Null-Terminator mit). Der Client muß natürlich auch dieses Kennzeichen kennen und die empfangenen Daten entsprechend auswerten.
-
Anders gehts wohl nicht ?
Wollte das eigentlich vermeiden, wird ganzschön anstrengend. Vor allem wenn ich berücksichtigen muss, dass send ein limit von 1024 byte hat, soweit ich weiss. Dann müsste ich davor wieder ein send verbrauchen, um mitzuteilen wie lang der String ist ?
Dachte das geht so in Ordnung, wie ich das gemacht habe, aber send() ist wohl nicht ganz so genau wie man sich das vorstellt.
-
send hat kein Limit von 1024 Byte. Und wieso ist es nicht so, wie DU es Dir vorstellst? Es sendet die Daten an den Empfänger, was hättest Du erwartet?
-
Ändere
send( clients[j].client, temp, strlen(temp) , 0 );in
send( clients[j].client, temp, strlen(temp) + 1 , 0 );Dann bekommt der Empfänger das String-Ende Zeichen '\0' mitgesendet.
-
Es hat kein Limit bei 1024 ? Hat es denn ein Limit ? Ich habe einmal diese Funktion für die maximale Msg-Size ausprobiert, ergibt bei mir aber immer 0.
Nun, wir wurde folgendes gesagt : send calls setzten gerne mal strings zusammen und reissen sie ausseinander, deswegen schreibt man sich package-header.Ohh, jetzt hab ich das alles schon umgeändert, sodass ein einziger String gesendet wir und der Client diesen dann unterteilt
Welche Variante wäre denn "besser" ? Wenn send() halt ein bestimmtes Limit hat ist das mit einem String relativ aufwenidiger. Allerdings werden bei meiner ersten Variante sehr viele send-calls gemacht und ich weiss nicht wie gut bzw wie schlecht das ist.
Danke auf jeden Fall schonmal für den Hinweis
-
Hmmmm schrieb:
Es hat kein Limit bei 1024 ? Hat es denn ein Limit ? Ich habe einmal diese Funktion für die maximale Msg-Size ausprobiert, ergibt bei mir aber immer 0.
Nun, wir wurde folgendes gesagt : send calls setzten gerne mal strings zusammen und reissen sie ausseinander, deswegen schreibt man sich package-header.Das Verhalten hast du ja schon in der Praxis kennengelernt
(als du deine Client-Namen übermitteln wolltest)Ansonsten dürfte das Socket-System schon dafür sorgen, daß die Daten in der günstigsten Form übertragen werden.
-
Naja, ob das an der von Belli erwähnten Sache lag oder am send() selber weiss ich leider nicht.
Bin schon wieder bei einem neuen Problem.
Laut MSDN : http://msdn.microsoft.com/en-us/library/bb775183(v=vs.85).aspx bräuchte ich hier nur den index + LB_DELETESTRING zu senden und schon würde das entsprechende item gelöscht werden. Allerdings wird bei mir IMMER das letzte Element in der Listbox gelöscht, sogar wenn ich index hardcode, zb :SendMessage ( GetDlgItem( hClientList[0] , ClientListBoxId ) , LB_DELETESTRING , 2 , 0 );. Es wird trotzdem das letzte Element gelöscht ;O
[quote = 'MSDN']
If an application creates the list box with an owner-drawn style but without the LBS_HASSTRINGS style, the system sends a WM_DELETEITEM message to the owner of the list box so the application can free any additional data associated with the item. [/quote]Das trifft zwar bei mir zu, kann aber nicht herrauslesen, dass das ein Problem für das Löschen des Eintrages an sich wäre. Ich könnte, falls ich wollte , halt durch WM_DELETEITEM weitere Informationen beziehen, aber das wars auch.
-
Hmmmm schrieb:
send calls setzten gerne mal strings zusammen und reissen sie ausseinander
Die setzen weder was zusammen, noch reißen sie was auseinander. Sie senden einfach die Daten an den Empfänger.
Aber: Wie ich oben schon mal in anderem Zusammenhang erwähnte, kann/darf man sich nicht darauf verlassen, dass ein Aufruf von recv haargenau das liest, was ein send geschickt hat.
Stell Dir das so vor:
send versendet die Daten an den Empfänger, die Daten werden in einem Puffer vorgehalten. Bei weiteren sends werden die nächsten Daten hinten angehängt, usw.recv beim Empfänger liest jetzt aus diesem Puffer. recv hat aber keine Ahnung davon, wieviel sends der Sender ausgeführt hat, es 'sieht' nur den Puffer und die darin befindlichen Daten und liest aus, was es kriegen kann.
Das kann 1. dazu führen, dass zB mit einem send 1000 Byte versendet werden, ein recv aber nur 300 Byte liest. Deshalb - wie in einem früheren Posting erwähnt - braucht man für die Kommunikation häufig ein Protokoll. Etwa in der Art, dass beim send immer erst 4 Byte mit der Länge der folgenden Message gesendet wird, recv diese 4 Byte liest und dann so lange weiterliest, bis es genau die entsprechende Anzahl Byte bekommen hat.
2. kann das zu dem von Dir beobachteten Verhalten führen, es wird zB 5 mal send mit je 1000 Byte ausgeführt; beim recv kann nun von 1 bis 5000 alles 'erwischt' werden ...
-
cooky451 schrieb:
Wenn überhaupt, dann geht das so:
class MyClass { public: static void foo(void *param) { std::cout << GetCurrentThreadId() << std::endl; } }; int main() { for (int i = 0; i < 50; ++i) CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(&MyClass::foo), 0, 0, 0); Sleep(20000); return 0; }Ich weiß aber nicht, welches Verhalten garantiert wird.
Falls du die CRT nutzt, sollten eh _beginthread/ex etc. herhalten.
Siehe
http://msdn.microsoft.com/de-de/library/kdzttdcb(v=vs.80).aspxDer Herr Richter hatte glaube ich auch mal einen Blogeintrag dazu geschrieben..
Nur so als Hinweis: Mit dem Cast nach LPTHREAD_START_ROUTINE den Kompiler zum Schweigen zu bringen ist nicht sehr nett. Verpasse der Thread Routine die korrekte Signatur, Rückgabetyp und Calling Convention und der Kompiler zeigt auch ohne Cast keinen Fehler mehr!!
-
Gut, dann werde ich wohl zum Anfang jeden Strings die größe mit übergeben. Dann sollte ich bei jedem recv()-call wohl auch prüfen ob rc < gesendeteGröße ist, wenn ja dann nochmal recv() callen, right ?
Aber bei meinem vorhin erwähnten Problem komme ich immernoch nicht weiter.
SendMessage ( GetDlgItem( hClientList[0] , ClientListBoxId ) , LB_DELETESTRING , 2 , 0 );-> Löscht immer das letzte Item der Listbox. Trotz des Hardcodings von index ( wPara ) ;O
-
Hmmmm schrieb:
SendMessage ( GetDlgItem( hClientList[0] , ClientListBoxId ) , LB_DELETESTRING , 2 , 0 );-> Löscht immer das letzte Item der Listbox. Trotz des Hardcodings von index ( wPara ) ;O
Nö. Das tut es nicht...
-
Bei mir leider schon

Screeni : http://imageupload.org/?d=4A0697231
-
theta schrieb:
..
Hast natürlich recht, sollte heißen:
static unsigned long __stdcall foo(void *param)Ich nutze irgendwie immer nur _beginthread und war zu faul die richtige Signatur zu suchen

@Hmmmm
Könntest du mir mal deinen ganzen Code (am besten gleich als VS Projekt, sonst halt einfach so) zuschicken (Mail über mein Profil)? Also falls das nicht irgendwie geheim sein soll oder so, denn das würde mich jetzt schon mal interessieren
-
Okay, gerne ;P
dazu muss ich mich aber eben erstmal reggen ( um deine Email zu sehen ) und das ganze compilefähig unter VSC++ 2010 machen. Ist immo immernoch unter devc++ und einige Sachen nimmt vsc++ nicht an ^^
-
Hi,..
Nochmal etwas zu CreateThread und Memberfunktionen:
http://www.c-plusplus.net/forum/278752Ich habe mir eine basisklasse geschrieben die ich als "handler" mit den methoden
vererbe:class _thread_handler: public _thread_member_serializer { protected: HANDLE hThread; DWORD dwThreadId; _thread::LockedSignalStruct tssSignal; public: virtual DWORD WINAPI run(LPVOID lpParam=0); //=0; virtual start(BOOL BlockTillStartupSignaled=FALSE,DWORD dwTimeout=0,DWORD StackSize=0); virtual stop(BOOL BlockTillEndSignaled=TRUE,DWORD dwTimeout=5000); HANDLE _get_handle(void); DWORD _get_id(void); }tssSignal hat noch (Inlerlockabel) member die den startup signalisieren und im member run(thread) signalisieren das dieser beendet werden soll (muss natürlich jeden zyklus abgefragt werden) um ein unsauberes Terminate zu vermeiden...
Damit kann man sauber und gut arbeiten ...
grüüße

-
@ zeusosc ;O Sieht iwie nice aus
Habe mich aber nur seeehr oberfächlich mit threads beschäftigt, ich glaube da kann man zieemlich in die Tiefe gehenOh man ey ... wieso wollen denn all die Funktionen auf einmal TCHAR's -.- Ich muss das komplett alles umschreiben lal. Auch widestrings nehmen damit es unter VSC++ 2010 compiled. Neeeeeeeervt xD
Heute abend sollte ich das fertig haben, dann schick ichs dir mal.