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 mit close geschlossen wird, sollte doch accept 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.
    Mit

    int 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.


Anmelden zum Antworten