in reply to unbuffered read from socket

If all of the data coming from $filehandle is plain text, why not use Perl's normal buffered file ops?
my $line = <$filehandle>; chomp $line;
Update: If, OTOH, you can't use the buffered ops, then I do think reading one character at a time is your best bet. But you can do better than appending the character with .= each time:
my $line; open my $linefh, \$line; until ($char eq "\n") { sysread($filehandle, $char, 1); print $linefh $char; } close $linefh;
The above requires Perl 5.8 I think. If you don't have that you can use IO::Scalar.

Update 2: I noticed that there's a Net::IRC module already out there. Might this work better for you than playing with sockets directly?

Replies are listed 'Best First'.
Re^2: unbuffered read from socket
by eyepopslikeamosquito (Archbishop) on Dec 29, 2004 at 03:42 UTC
    I do think reading one character at a time is your best bet

    It's generally poor form and very slow to read one char at a time with sysread(); it's unbuffered, as is C's read(), so you're making a system call per character. Ouch. If you ask for 1024 bytes and only one is available, it will be returned in $buf, sysread returning the number of chars actually read. For example:

    my $buf; my $nread; open(my $filehandle, '<', 'f.tmp') or die "error open: $!"; while ($nread = sysread($filehandle, $buf, 1024)) { print "nread=$nread buf='$buf'\n"; }

    To illustrate my point, this program:

    use strict; my $buf; my $nread; open(my $filehandle, '<', 'f.tmp') or die "error open f.tmp: $!"; binmode($filehandle); open(my $fhout, '>', 'g.tmp') or die "error open g.tmp: $!"; binmode($fhout); while ($nread = sysread($filehandle, $buf, 1)) { print $fhout $buf; } close($filehandle); close($fhout);
    takes 27 seconds to copy file f.tmp to g.tmp, where f.tmp is perl-5.8.6.tar.gz (about 12 MB). If you simply change:
    sysread($filehandle, $buf, 1)
    above to:
    sysread($filehandle, $buf, 1024)
    the time reduces to 0.2 seconds.

      Yes, that is certainly true, but it does increase complexity because the developer then has to do his own buffering. IOW, he only wants one line but he might well end up reading more than that, up to 1k so that has to be stored somewhere.

        Good point Errto, you drove me to dig out the Perl Cookbook recipe 7.23, which, to my horror, also does a sysread() of one character at a time (and with no performance caveat). I wonder if anyone has encapsulated a nice clean buffering scheme to work in harness with select() and sysread()? Update: quick look on CPAN found nothing, but Lincoln Stein's book "Network Programming with Perl" (Chapter 13) features an IO::Getline module that seems to be what I'm after, namely "line-oriented reading from sockets/handles with access to internal buffer".

        One important point made in this recipe is that you must use unbuffered sysread() (and not the buffered I/O functions) with select() because select's response does not reflect user level buffering.

        Update: Found this interesting bit of history from comp.lang.perl.moderated (15-Jan-1999) describing a mythical sysreadline() function requested by Larry but, alas, never implemented.

Re^2: unbuffered read from socket
by Forsaken (Friar) on Dec 29, 2004 at 10:40 UTC
    the problem is that using buffered IO combined with select is a bad idea from what i understand, and i have seen some flakey behaviour from it, so it might indeed be a bad idea.

    Net::IRC is discontinued and has been replaced by POE::Component::IRC which, although most definitely a terrific module, is not quite what I'm looking for.

    I'll give the option you listed using print to a filehandle a try, although right now cpu time seems to be very reasonable. even when spamming the bot with large amounts of text cpu time never exceeds 1%. dunno what'll happen when more processing is added though, so any improvement suggested is worth a try.