http://www.perlmonks.org?node_id=913153

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

Hi,

I've used IO::Select package and can_read to do polling in my socket. Here is my question,

while(1) { my ( @read_sockets ) = $SELECT->can_read(5); if ( @read_sockets ) { foreach my $fh ( @read_sockets ) { my $data = <$fh>; print "Got data from server, $data"; $data =~ s/\n$//; } } }

When server sends me multiple line messages. can_read returns the socket handle and I read the first line of it(as per the above code). I thought if I do can_read again, I'll get the socket handle returned as some data is not yet read. But, can_read is blocking and not returning the socket handle.

So, what is the better way to use can_read for multi line messages??

Replies are listed 'Best First'.
Re: IO::Select - reading multiple lines
by zentara (Archbishop) on Jul 07, 2011 at 12:04 UTC
    You might want to use sysread instead of my $data = <$fh>. See sysread and syswrite in tcp sockets for example.
    # as a start change my $line = <$fh>; #to sysread $fh, my $line, 1024;,
    The basic issue is that <$fh> does a buffered read from the socket. It won't return from the read call until $/ (defaults to "\n") is encountered on the channel. IO::Select::can_read just means that there is data on the channel, it does not necessarily mean that there is a full record (defined as: a chunk terminated with an occurence of $/) waiting on the channel.

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
      That is indeed the correct solution (to use sysread). However, it's worse than simply because there's no newline.

      select generally doesn't work properly if you mix in buffered reads and writes; select will perpetually think something is readable, or nothing is readable, because the buffering has over-read or under-read on the handle.

      This means that whenever you're using select, either directly or indirectly through IO::Select or some event loop, then you must use sysread and syswrite (not print, <$fh>, read(), etc.).

      You often end up doing your own buffering with sysread and syswrite, because often you're still dealing with line-oriented protocols. This is fairly boilerplate stuff, and it's recommended to use an event loop that does most of it for you (e.g. POE, Event, IO::Async, etc.).

      Monks,

      I've many questions raising now., Let me tell what's in my mind.

      So, is it a very worse idea to use <$fh> to read from a socket? Because, it is failing straight away without doing lot of magic(stuffs) in the code.

      Server side
      while(@ready = $sel->can_read) { if($fh == $lsn) { # Accept the socket $new = $lsn->accept; $sel->add($new); print "New client accepted\n"; print $new "abc\n"; print $new "abcd\n"; print $new "abcde\n"; print $new "abcdef\n"; } else { # Process socket $a = <$fh> ; if (not defined $a) { $sel->remove($fh); $fh->close; print "Client closed\n"; } else { print $a; } } }
      Client side
      while(@ready = $sel->can_read) { foreach $fh (@ready) { my $rr = <$fh>; exit if ( not defined $rr ); print $rr; } }

      In the above sample, client is receiving only abc(first message) sent by server. When server quits, can_read is returning and client is receiving the remaining messages, not blocking. Getting messages one after another.

      Then, I tried with sysread as suggested here. When using sysread, should I read byte by byte till '\n'? Because, I don't know the size of the message. Is it a good way to read byte by byte, do concatenation and then process the message?(I don't think so.)

      Please, explain me some way to write a error free way(pleasant way too) to receive messages in socket.. or let me know what am I doing wrong.

      Thanks.
        is it a very worse idea to use <$fh> to read from a socket

        Yeah, you are best off using sysread, and there are a few ways to use sysread, depending on your situation, you can put it in various staement forms

        while( sysread $fh, $str, 8192, length $str ) { #or do { $rc = sysread(FH, $buff, 5000000, length($buff)) ; } while ($rc #or if ( sysread( $cli, $buffer, 1024 ) ) {} # etc etc

        I'm not really a human, but I play one on earth.
        Old Perl Programmer Haiku ................... flash japh