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

Okay... I'm trying to finish my socket handling routine, and when I use the sub handle I want to close out the client socket, but when I use what you see it dies with the following message:

Unable to Close 'IO::Socket::INET=GLOB(0x1ab2e88)': Bad file descriptor

I believe I just need to call Close($client) correctly to make sure the $client is the TRUE filehandle name.

Any suggestions?

Thanks,
Mike Slattery
use strict; use IO::Select ; use IO::Socket; use constant BUFSIZE => 1024 ; sub logmsg { print "INFO: @_\n" } my $port = shift || 2345; my $lsn = new IO::Socket::INET(Listen => 1, LocalPort => $port) ; my $sel = new IO::Select($lsn) ; my %inbuffer; my %ready ; my ($buf,$fh,$client,$new,$rVal) ; my (@items) ; logmsg "server started on port $port"; while (@items = $sel->can_read) { foreach $fh (@items) { # It's the Listen Socket if ($fh == $lsn) { $new = $lsn->accept ; $sel->add($new) ; # It's any Other Socket } else { $rVal = sysread($fh,$buf,BUFSIZE) ; unless (defined($rVal) && length $buf) { #Handle EOF print "EOF: $fh\n" ; delete $inbuffer{$fh}; $sel->remove($fh); close($fh) ; next ; } $inbuffer{$fh} .= $buf ; #Check for complete request if ($inbuffer{$fh} =~ /\n$/) { $inbuffer{$fh} =~ s/[\015\012]+$// ; push( @{$ready{$fh}}, $inbuffer{$fh} ); delete $inbuffer{$fh} ; } #Handle ready requests foreach $client (keys %ready) { handle($client); } delete $ready{$client}; } } } sub handle { # requests are in $ready{$client} my $client = shift; my $request; foreach $request (@{$ready{$client}}) { if ($request =~ /^quit$/) { print "Client: '$client' Requesting QUIT\n" ; $sel->remove($client); close($client) || die "Unable to Close '$client': $!\n" ; last; } print "Client: '$client' Req: '$request'\n" ; } delete $ready{$client}; }

Replies are listed 'Best First'.
Re: Cant find out how to get the real file handle name!
by japhy (Canon) on Apr 16, 2002 at 18:44 UTC
    All hash keys are strings; so if you put an object (or any other reference) as the key in a hash, it will be a string in that hash. Example:
    use strict; my $x = "foo"; my $y = \$x; my %foo = ($y => "bar"); for (keys %foo) { print $$_ }; # hoping to print 'foo'
    That code dies saying "can't use string 'SCALAR(0x...)' as scalar reference..." or something like that. A solution is to keep two hashes.
    my %foo = ($y => "bar"); my %refs = ($y => $y);
    Now you can access $refs{$_} to get at the REAL reference.

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a (from-home) job
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: Cant find out how to get the real file handle name!
by perlplexer (Hermit) on Apr 16, 2002 at 18:24 UTC
    To start with:
    if ($fh == $lsn) { # this does not do what you think it does
    If you want to compare filehandles, use fileno()

    Next:
    $inbuffer{$fh} .= $buf; # Hash keys are stored as STRINGS. ... foreach $client (keys %ready) { # So, when you are finally here # $client is just a STRING # It is no longer a reference handle($client); }


    --perlplexer

      If you really need to use references as keys, use the standard Tie::RefHash module which won't stringify them.

        Thanks for answering!

        This seems like what I want to do so thanks!!!

        BTW, do you think there is a better way to maintain the list of incoming sockets?

        Thanks,
        mslattery

        Fletch,

        Thank YOU very much.

        Just adding the Tie::RefHash and of course Tie(ing) the hash did the trick. All works great now!

        Thanks,
        Mike

      First off, thanks for answering...

      The $fh==$lsn works, but that doesnt mean it's correct. I'll look into using fileno() but my understanding is that when you use IO::Socket it doesnt work EXACTLY like filehandles under WIN32 (which is my platform, should of said earlier eh?).

      As for the stored as strings, I know.. that's my problem. I'll look into TIE I guess! :)

      Thanks Again,
      mslattery