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

Hi Monks,

I do speak to my kid, but it does not listen ;-( Nothing arrives there.

The problem here is, that what should be send coems once and a while, while the kid should send, what it has got exactly every minute.

So I am forking a kid to sleep until full minute and then I want to read what has come and send it, but the can_read(0) returns always an empty array..

this is the fork and the parent-talk

my $pid = open(PIP, "|-");# open to write if ( !$pid ) { # I'm the child sendToClient( $SOCKET ); # give the Socket =ok exit; } else { # I'm parent talking to the kid print PIP "Are you there?\n"; my $n = 0; while (1) { # just to test.. print PIP "hmm, No. ",++$n,"\n"; # kid ?? print "hmm, No. $n\n"; sleep 1;#control -> ok! }
The Kid executes this
sub sendToClient { my $SOC = ( shift ); my $HDL = IO::Select->new( \*STDIN ); while ( $HDL->exists( \*STDIN ) ){ # ok! mySleepToFullMinute(); # ok, not the problem my @lines = $HDL->can_read( 0 ); # allways empty??? foreach my $l (@lines) { print $SOC $l; # nothing to send?? } } }
But @lines is allways empty - why && how to change?
What is my mistake?

Thanks in advance and a nice Subday,
Carl

Replies are listed 'Best First'.
Re: forked kid can't read from IO::Select->can_read
by polettix (Vicar) on May 22, 2005 at 13:45 UTC
    You're suffering from multiple diseases.

    First of all, try to give us something that should work cut-and-paste if there was no error. This helps us concentrate on the problem you have instead of working out a new example from the scratch, and helps you have more answers.

    Then, IO::Select says:

    can_read ( [ TIMEOUT ] ) Return an array of handles that are ready for reading. "TIMEOUT" is the maximum amount of time to wait before returning an empty list, in seconds, possibly frac- tional. If "TIMEOUT" is not given and any handles are registered then the call will block.
    So it doesn't return the lines which wait to be read, but the handles that have data and that you can read from.

    Last, but not least, you're maybe suffering from buffering. You don't provide much information about SOCKET/SOC, but note that if it buffers you could wait a long time before something is output. Unless it's really some socket, in which case you'd not.

    Here's a working example, you'll be able to adapt it to your case easily. Note that the child sleeps 5 seconds, then checks for data in handles and reads from them.

    #!/usr/bin/perl use warnings; use strict; use IO::Select; my $pid = open(PIP, "|-"); if ($pid < 0) { die "open(): $!"; } elsif ($pid > 0) { print scalar localtime time, " - Parent: sending something to chil +d\n"; print PIP "Hi, son!\n"; print scalar localtime time, " - Parent: waiting for child to fini +sh\n"; close PIP; print scalar localtime time, " - Parent: exiting\n"; } else { my $selector = IO::Select->new(\*STDIN); print scalar localtime time, " - Child: just born!\n"; sleep(60); my @handles = $selector->can_read(0); if (@handles) { print scalar localtime time, " - Child: there are " . scalar(@ +handles) . " handles ready for reading\n"; # It can only be STDIN... my $line = <STDIN>; chomp($line); print scalar localtime time, " - Child: parent says: [$line]\n +"; } print scalar localtime time, " - Child: exiting\n"; exit(0); } __END__ Sun May 22 15:43:48 2005 - Parent: sending something to child Sun May 22 15:43:48 2005 - Child: just born! Sun May 22 15:43:48 2005 - Parent: waiting for child to finish Sun May 22 15:44:48 2005 - Child: there are 1 handles ready for readin +g Sun May 22 15:44:48 2005 - Child: exiting Sun May 22 15:44:48 2005 - Parent: exiting
    As a final note, always check the return status of open, it can fail!

    Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

    Don't fool yourself.
      Frodo,

      ahh! (&& uups, sorry)

      I understand my mistake, I thought that can_reads returns the buffered lines, but it returns only the 'readable' handles - ok.
      But now I'm thrown back to my old problem:

      while (<HANDLE>) {..}
      waits until a EOL is sent and then executs the the block {..}.
      So what if I don't want to wait for that EOL, but what if I have to send what I have got exactly at the full minute?

      So frankly spoken how can I (the kid of course) read from STDIN all what is there and return immediately if nothing is there anymore?

      Thanks in advance,
      Carl

        Using the <> way of reading from a socket means you're using buffered reading, which is a bad idea when using select, or in this case IO::Select. Instead I would recommend using sysread() to do the actual reading. Now, the nice thing about sysread() is that every time it does a read, it returns the amount of bytes actually read in. So if you were to do for example:
        my $scalar; my $bytes = sysread(FILEHANDLE, $scalar, 1024);
        and $bytes turns out to be less than 1024, then it's a pretty safe assumption that there's nothing left. If on the other hand you get the full 1024 you can just go ahead and do another read, and so on, and so on.


        Remember rule one...
        Using regular buffered reads, you don't really have much control over it. Most likely, it will block even if you sent exactly one line, because at the time of the actual (hidden) sysread, it doesn't know that there's a full line available -- it just reads a fixed number of bytes.

        So you have two options. One is to do a select and a sysread for every individual byte. This is probably easier but very inefficient.

        Another is to change STDIN to be nonblocking, and try to sysread large chunks at a time. Keep trying until sysread returns undef, and then check $!{EWOULDBLOCK}. Completely untested:

        sub read_available { my ($fh) = @_; my $data = ''; while (1) { my $buf; my $nread = sysread($fh, $buf, 4096); if (defined $nread) { if ($nread == 0) { # End of file, so we have everything we'll ever get return ($data, 1); } else { $data .= $buf; } } else { if ($!{EWOULDBLOCK}) { return ($data, 0); } else { return; # Error } } } } . . . # Set STDIN nonblocking IO::Handle->new_from_fd(fileno(STDIN), "r")->blocking(0); . . . # If select says that STDIN is readable... my ($data, $eof) = read_available(*STDIN) or die "Error reading stdin: $!";

        I really should test this once, but hopefully it gives the right idea. Seems like a correct version of this routine ought to be in a FAQ somewhere. Or maybe it is; I didn't check.

        I agree with the previous answers, you'd jump to a lower-layer sysread to do this.

        I usually use select immediately before each sysread, trying to read big chunks of data at one time. But I do this because, in the mean case, I manage more than one handle at one time, so I use select to make an intelligent wait upon multiple sources. If you only have to read from one handle, you'd probably go for a non-blocking read (if you have to do something else while data is arriving, of course).

        And yes, I admit that I cheated a bit in my answer, because I added a "\n" in the data sent by the father, and a chomp in the kid :)

        Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

        Don't fool yourself.
Re: forked kid can't read from IO::Select->can_read
by thcsoft (Monk) on May 22, 2005 at 12:10 UTC
    i'm afraid your code is weird. who told you that opening a pipe forks to a new process, which then is under control by perl?
    perldoc-f open says:
    If the filename begins with '|', the filename is interpreted as a comm +and to which output is to be piped, and if the filename ends with a ' +|', the filename is interpreted as a command which pipes output to us +. See "Using open() for IPC" in perlipc for more examples of this.
    the crucial words are: the filename is interpreted as a command to which output is to be piped - which means that the new process's control is up to the shell, and no longer to perl.
    if you really want to fork to a process you can talk to, you will have to use one of the usual IPC methods. for convenience reasons i'd suggest you use sockets. but that's my personal opinion.

    language is a virus from outer space.
      You might want to read open a bit more carefully. Further down it says,
      If you open a pipe on the command ’-’, i.e., either ’│-’ or ’-│’ with 2-arguments (or 1-argument) form of open(), then there is an implicit fork done, and the return value of open is the pid of the child within the parent process, and 0 within the child process. (Use "defined($pid)" to determine whether the open was successful.) The filehandle behaves normally for the parent, but i/o to that filehandle is piped from/to the STDOUT/STDIN of the child process. In the child process the filehandle isn’t opened--i/o happens from/to the new STDOUT or STDIN.
      Hi thsoft,

      for here: perlipc.html#Safe-Pipe-Opens
      I took and changed:

      $pid = open(KID_TO_WRITE, "|-"); if ($pid) { # parent print KID_TO_WRITE @some_data; close(KID_TO_WRITE) || warn "kid exited $?"; } else { # child while (<STDIN>) { ... print ; # child's STDIN is parent's KID } exit; # don't forget this }
      So this shouldn't be the problem?