Sockets: blockierendes accept bricht bei close nicht ab
-
Hi!
Hab mich halb tot gesucht, bis ich den Fehler gesehen hab. Ich habe einen blockierenden Socket, der in einem Thread mit
accept
Verbindungen annehmen soll. Soweit so gut, wenn während des "accept"-Wartens in einem anderen Thread der Socket mitclose
geschlossen wird, sollte dochaccept
mit irgendeinem Fehlercode abbrechen?
Das ist bei mir jedenfalls nicht der Fall, Linux Kernel 2.6.24-19 mit Ubuntu 4.2.3.Testcode:
#include <fcntl.h> #include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> #include <errno.h> #include <iostream> int s = -1; void* thread_func( void* ) { sockaddr_in a; socklen_t a_size = sizeof(a); ::accept( s, reinterpret_cast<sockaddr*>(&a), &a_size ); // Wird nie ausgegeben: std::cout << "Accepting done" << std::endl; } int main() { s = ::socket( PF_INET, SOCK_STREAM, 0 ); if ( s == -1 ) return 0; // Set blocking int status = fcntl( s, F_GETFL ); fcntl( s, F_SETFL, status & ~O_NONBLOCK); // Bind & listen sockaddr_in sa; memset( sa.sin_zero, 0, sizeof(sa.sin_zero) ); sa.sin_addr.s_addr = htonl(INADDR_ANY); sa.sin_family = AF_INET; sa.sin_port = htons( 6781 ); // Reuse port if ( ::bind( s, reinterpret_cast<sockaddr*>(&sa), sizeof(sa) ) == -1 ) return 0; if ( ::listen( s, 0 ) == -1 ) return 0; pthread_t t = -1; if ( pthread_create( &t, 0, &thread_func, 0 ) ) return 0; // Wait & close socket - accept in the other thread should return. sleep( 2 ); std::cout << "closing now.." << std::endl; int r = close( s ); std::cout << "closing s: " << r << std::endl; // Join klappt natürlich nicht, wenn accept nicht abbricht. std::cout << "trying to join.." << std::endl; pthread_join( t, 0 ); std::cout << "joined.." << std::endl; }
Ausgabe:
closing now... closing s: 0 trying to join...
Der Socket funktioniert ansonsten (auch hier im Testcode) ganz gut/normal, kann mich hier z.B. auch mit dem Browser zu dem Socket verbinden.
Noch was: Wenn sich vorher oder beim "join"en ein Client zum Socket verbindet, klappt alles wie gewollt (hier sowieso, aber im richtigen Code).
accept
läuft eigentlich in einer Schleife.edit: Zum Ausprobieren: g++ bla.cpp -o bla -lpthread
Kann denn jemand bestätigen, dass accept abbrechen sollte? Und verhält sich bei jemandem der Code anders als bei mir?
-
Hallo,
ich habe es ebenfalls unter Ubuntu getestet. Die Ausgabe ist gleich.
Mitint r = shutdown (s, 2)
gibt es diese Ausgabe:
closing now..
Accepting done
closing s: 0
trying to join..
joined..Vieleicht verhält es sich mit file-Deskriptoren bei Threads wie bei Prozessen?
-
Juchu, danke dir! Ich weiß zwar immer noch nicht, warum close<->accept nicht funktioniert, aber dieser Work-Around reicht völlig
linuxbie_logout schrieb:
Vieleicht verhält es sich mit file-Deskriptoren bei Threads wie bei Prozessen?
Wie meinst du das?
-
Aus mehreren Threads heraus auf den selben Filedeskriptor zuzugreifen ist nicht spezifiziert. Es ist insbesondere nicht spezifiziert, was passieren soll, wenn der Filedeskriptor geschlossen wird, während ein anderer Thread damit arbeitet. Daher rate ich von solchen Dingen ab.
Besser ist es, nicht blockierend auf dem accept zu sitzen, sondert accept aufzurufen, nachdem ich mich mit poll vergewissert habe, daß ein Verbindungsrequest gekommen ist. Einen poll kann ich über eine Monitor-pipe unterbrechen. Diese Verhalten ist dann wohl definiert und garantiert mir, daß das auf jedem Posix-System funktioniert.