in reply to Re^2: IO::Socket tutorial
in thread IO::Socket tutorial

I don't even remember what got me thinking that IO::Socket's can be used as file descriptors

Technically they can be used like handles (not descriptors), they're subclasses of IO::Handle. But as you discovered, doing a readline on them is blocking; from my experience I very much prefer non-blocking operations, and those are IMHO best abstracted via an event-based interface.

In terms of example code, I should have been more specific: a Short, Self-Contained, Correct Example.

Replies are listed 'Best First'.
Re^4: IO::Socket tutorial
by BernieC (Monk) on Feb 19, 2020 at 21:05 UTC
    I seem to have replied but forgot to post it... duh. Anyhow, I'm thinking of sticking with IO::Select and it looks very easy. I create a new Select object initialized to my TCP connection, then I can do a can_read with a timeout, and if it doesn't time out I can use ->getlines to suck up what was sent. If that's all that I was expecting {the returned stuff is terminated by a line with just a ".", as with RCS and unix-mail} I'm done, otherwise I go back and can_read again. Either I get all I needed or a can_read returns a timeout. Seems pretty easy... I can handle the recovery code when it times out. THANKS!!
      I'm thinking of sticking with IO::Select and it looks very easy. ... then I can do a can_read with a timeout, and if it doesn't time out I can use ->getlines to suck up what was sent

      No, unfortunately it's not that easy. The reason is that can_read will fire even if there's only a single byte waiting to be read, and readline and friends will still hang because it's looking for a full line, which the server might not have sent.

      srv.pl:

      use warnings; use strict; use IO::Select; use IO::Socket; my $sock = IO::Socket::INET->new( Listen=>1, ReusePort=>1, LocalAddr=>'127.0.0.1', LocalPort=>1235 ) or die "sock: $@"; my $sel = IO::Select->new($sock); while ( my @ready = $sel->can_read ) { for my $fh (@ready) { if ($fh == $sock) { my $cli = $sock->accept; print "New client\n"; $sel->add($cli); syswrite $cli, "x"; } } }

      cli.pl:

      use warnings; use strict; use Data::Dumper; use IO::Select; use IO::Socket; my $sock = IO::Socket::INET->new( PeerAddr=>'127.0.0.1', PeerPort=>1235 ) or die "sock: $@"; my $sel = IO::Select->new($sock); while ( my @ready = $sel->can_read(1) ) { for my $fh (@ready) { print "Attempting to read...\n"; # all of these hang! #print Dumper($fh->getlines); #print Dumper($fh->getline); print Dumper(scalar <$fh>); } }

      Note these aren't complete examples as they are oversimplified and lack error handling. Anyway, sure, you could implement your own routine to read the socket byte-by-byte until you've got a full line, but that's a wheel that's been re-implemented a million times (I've done it several times myself). Again: I strongly recommend you use a library that already provides this functionality!

        Thanks for the correction. I wondered how can_read and getline{s} interacted {answer: not at all}. I hear you about not reinventing the wheel and I'll look again at POE.. it seems awfully complicated for something as simple as what I need {basically *nothing* more than an unblocking read} Is there a less complicated package that provides the simple functionality I need?

        I confess that I'm a bit surprised that IO doesn't provide that facility. I could see it implementing a version of getline{} that took a timeout and gave you either the line you asked for or an error. I expect that {as you said} that functionality keeps getting reinvented, so it is a bit odd that over the years no one has added that to the IO family.

        Many many years ago I wrote a server in Perl and I had to do just as you said: the low-level sub had to read a byte at a time then assemble the response and return a complete line. I only remember it being kinda clunky but worked. And I wish I still had the code I wrote to do that :)