Evgenij has asked for the wisdom of the Perl Monks concerning the following question:

Hi everybody!

I cannot explain why server doesn't close TCP session.

Code:
#!/usr/bin/perl -w use threads ('yield', 'stack_size' => 64*4096, 'exit' => 'threads_only', 'stringify'); use IO::Socket::INET; my %shared_value :shared; sub sleeping { { lock %shared_value; #do somesing with %shared_value #... } sleep 60; } my $commandLinePrefix = "Command: "; sub listeningClient { my $client = shift; my $clientHost = $client->peerhost; $client->autoflush(1); print $client "Welcome to $0; type help for command list.\n$comman +dLinePrefix"; while ( <$client> ) { next unless /\S/; if ( /quit|exit|^q\n?\r?$/i ) { print $client "Closing connection\n"; last; } elsif ( /^sleep|^s\n?\r?$/i ) { threads->create( \&sleeping )->detach(); } else { print $client <<EOF; COMMANDS: quit|exit|q - quit from current session sleep|s - fall asleep EOF } } continue { print $client $commandLinePrefix; } close $client; } sub startServer { $IP = shift || 'localhost'; $PORT = shift || 9000; $server = IO::Socket::INET->new( Proto => "tcp", LocalAddr => $IP.':'.$PORT, Listen => SOMAXCONN, Reuse => 1); unless( $server ) { print "can't setup server. Error: $@\n"; exit; } print "[Server $0 accepting clients]\n"; while( my $connection = $server->accept() ) { my $thr = threads->create( \&listeningClient, $connection ); close $connection; } } sub main { my $ip = 'localhost'; my $port = 9000; use Getopt::Long; GetOptions( "ip=s" => \$ip, "port=i" => \$port ); startServer( $ip, $port ); } main();

Testing the server:

$ telnet 0 9000 Trying 0.0.0.0... Connected to 0. Escape character is '^]'. Welcome to ./strange.pl; type help for command list. Command: sleep Command: quit Closing connection

I expect than connection is closed immediately but connection is closed in a minute.

How to call "sleeping" function in a new thread and allow to close the session immediately (quit command)?

Replies are listed 'Best First'.
Re: unclear TCP client session block
by Eliya (Vicar) on Aug 23, 2011 at 14:35 UTC

    I think you need to close the connection in the thread that's running 'in the background'. Otherwise, the telnet client will wait for that duplicated connection to be closed, before it quits itself.

    When I modify your code as follows, it works for me, i.e. telnet quits right away, as you expected:

    sub sleeping { close shift; ... } ... elsif ( /^sleep|^s\n?\r?$/i ) { threads->create( \&sleeping, $client )->detach(); } ...

      Thank you Eliya! It's working!

      But why the thread that's running 'in the background' must know about connection?

      It's better if sleeping function knows only how to sleep and listeningClient function knows how to work with client.

      May be it's a bag in perl thread implementation?