Sockets+Threads
-
Genau so ist mein Programm ja auch aufgebaut - und da wo ClientConnect steht, starte ich den neuen Thread. Also nach dem accept.
Wenn ich das accept so stehen lasse, funktioniert es ja auch. Weil das accept blockiert. ich will den Server aber auch wieder beenden können. Dazu muss das accept aufhören zu accepten und der socket muss geschlossen werden.
damit ich dem accept sagen kann, "hör auf", starte ich vor dem accept mit select ein timeout. Sobald das Timeout drin ist, habe ich das Problem, dass mein Thread2 nach dem CloseSocket irgendwo im Thread1 weiter macht.
Das ist ja auch das eigentliche Problem: Thread2 befindet sich nach dem close an einer Position im Code an der eigentlich Thread1 ist. Thread2 versucht dann genau wie Thread1 ein accept auf Socket1 zu machen.
Meine Vermutung:
1. Thread2 betritt CloseSocket: und übergibt seine RückSprungAdresse A500 2. Thread1 betritt accept: und übergibt seine RücksprungAdresse A200 !!! damit wird die RückSprungAdresse von Thread2 überschrieben !!! 3. Thread2 ist mit CloseSocket fertig und will weiter machen. Das System gibt ihm die RückSprungAdresse A200, ander eigentlich Thread1 arbeitet. 4. Thread1 ist fertig und macht auch an der Adresse A200 weiter
-
Das ist mir zu hoch....
-
Das Threadsystem von Windows funktioniert bestens, genauso wie WinSock. Dein 2. Thread müsste sich doch beenden, wenn der Client disconnectet ist. Wo ist dann das Problem? Socket freigegeben - Thread beendet. Du kannst theoretisch ein blockierendes Select laufen lassen und den Socket in einem anderen Thread schließen, wenn du den Server beenden willst. Dann kehrt accept() mit einem Fehler zurück und du kannst dir die ganze Timeout-Geschichte sparen. Wenn du Sachen wie AcceptEx() verwendest, kann man die Overlapped-Operationen sogar ganz sauber mit CancelIo() stoppen.
-
matti83 schrieb:
Thread2 befindet sich nach dem close an einer Position im Code an der eigentlich Thread1 ist.
Geh hier bitte mal einen Schritt zurück, und beschreibe, welche konkrete Beobachtung dich zu dieser Schlussfolgerung führt.
-
Hier ein Auszug der Console des Servers
Der AcceptThread hat die ID 800 auf dem Socket 1896
Dann liefert das Accept den Socket 1784 und startet
den Thread 2044.In Zeile 21 und 22 ist Thread 2044 dabei den Socket 1896 zu benutzen
01 Accept: 1896 vvvvvvvvvvvvvvvvvvvv tid: 800 02 ** Hier wurde eine Verbindung aufgebaut – neuer Socket+Thread ** 03 Read: Socket: 1784 END select tid: 2044 04 Read: Socket: 1784 Socket.cpp:407 tid: 2044 05 Accept: 1896 -------------------- tid: 800 06 Accept: 1896 ^^^^^^^^^^^^^^^^^^^^ tid: 800 07 Accept: Socket: 1896 Socket.cpp:218 tid: 800 08 Accept: 1896 vvvvvvvvvvvvvvvvvvvv tid: 800 09 Read: Socket: 1784 END select tid: 2044 10 Read: Socket: 1784 Socket.cpp:407 tid: 2044 11 Accept: 1896 -------------------- tid: 800 12 Accept: 1896 ^^^^^^^^^^^^^^^^^^^^ tid: 800 13 Accept: Socket: 1896 Socket.cpp:218 tid: 800 14 Accept: 1896 vvvvvvvvvvvvvvvvvvvv tid: 800 15 Read: Socket: 1784 END select tid: 2044 16 Read: Socket: 1784 BEG read tid: 2044 17 Read: Socket: 1784 END read tid: 2044 18 ** Hier wurde der Socket geschlossen und Recv gibt 0 zurück ** 19 Read: Socket: 1784 BEG release tid: 2044 20 release Socket: 1784 Socket.cpp:543 tid: 2044 21 Accept: Socket: 1896 Socket.cpp:218 tid: 2044 22 Accept: 1896 vvvvvvvvvvvvvvvvvvvv tid: 2044 23 Accept: 1896 -------------------- tid: 800 24 Accept: 1896 ^^^^^^^^^^^^^^^^^^^^ tid: 800 25 Accept: Socket: 1896 Socket.cpp:218 tid: 800 26 Accept: 1896 vvvvvvvvvvvvvvvvvvvv tid: 800
-
vvvvvvvvvvvvvvvvvv Kommt vor dem Select()
------------------ Kommt vor dem Accept() / Read()
^^^^^^^^^^^^^^^^^^ Kommt nach dem Accept() / Read()
-
Wie gibst Du denn diese Zeile aus? Woher hast Du die ThreadId?
-
cout << "Text" << socket << " tid: " << GetCurrentThreadId() << endl;
-
Dann verwendest Du in Deinem Worker-Thread einen falschen Socket...
-
Okay.. was sagt dir das?
-
wie meinst du denn das?
-
Du hast ein Fehler in Deinem Code!?
-
Da geh ich auch mal von aus, dass ich ein Fehler in meinem Code habe.
Aber ich komm nicht drauf welchen. Dieses Verhalten macht für mich kein Sinn.An der Thread-Sicherheit liegt es also nicht - meinst du.
Der Socket kann auch nicht falsch sein. Ist ja nur ein Integer/Long/FileDescriptor und es geht ja auch alles, bis ich den Client schließe.
Was mich verwundert, ist dass alles prima funktioniert, wenn ich das select() vor dem accept() weg lasse und accept() voll blockiert.
-
struct timeval m_timeout; struct sockaddr_in new_socket_m_addr; memset( &new_socket_m_addr, 0, sizeof( new_socket_m_addr ) ); socklen_t addrlen = sizeof( new_socket_m_addr ); m_timeout.tv_sec = 2; m_timeout.tv_usec = 0; while( true ){ fd_set readfds; FD_ZERO(&readfds); FD_SET(m_sock, &readfds); int ret = 0; ret = select( 0, &readfds, 0, 0, &m_timeout ); if( ret > 0 ){ newSock_sock = accept( m_sock, (struct sockaddr*)&new_socket_m_addr, &addrlen ); return newSock_sock; } }
-
Fang noch mal bei 0 an. Und dann ganz langsam, Schritt für Schritt, voranarbeiten.