Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I do proper IO::Select error handling?

Tags:

io

select

perl

I'm going through docs and howtos I'm finding on proper usage of IO::Select in terms of network socket communications. I think I've got my head wrapped around most of it.

However, I'm still kind of fuzzy on proper error handling. Say I've something similar to the following code running inside an object. Yes, I do realize it's messy, I should integrate IO::Select into the object and not the socket fh itself, I shouldn't recreate the IO::Select each time through the loop, I'm iterating over what can only ever be a single returned filehandle, etc. However, this keeps the example simple.

This is just a client connecting to a server, but one which I want to be able to properly handle network level errors such as packet loss.

Edit: $self->sock() returns just an opened IO::Socket::INET socket.

sub read {
    my $self = shift;
    my($length) = @_;   ### Number of bytes to read from the socket

    my $ret;

    while (length($ret) < $length) {
        my $str;

        use IO::Select;
        my $sel = IO::Select->new($self->sock());

        if (my @ready = $sel->can_read(5)) {  ### 5 sec timeout
          for my $fh (@ready) {
            my $recv_ret = $fh->recv($str, $length - length($ret));
            if (!defined $recv_ret) {
              MyApp::Exception->throw(
                message => "connection closed by remote host: $!",
              );
            }
          }
        }
        else {
          ### Nothing ready... we timed out!
          MyApp::Exception->throw(
                  message => "no response from remote host",
             );
        }
        $ret .= $str;
      }

      return $ret;
}
  • Do I need to be checking the return from recv, or are errors that would affect it going to be showing up in the IO::Select object?
  • Am I properly handling timeouts, or is my logic set up wrong?
  • IO::Socket makes mention of an exception existing on a socket filehandle, for out of band errors and other issues. Should I be checking this in the event of a timeout? How? Or is it unimportant and OK to ignore?
  • Are there any other exception cases I should be handling for proper behavior?
like image 431
Oesor Avatar asked Nov 15 '22 03:11

Oesor


1 Answers

1) I would check just in case. When it comes to select(2), defensive programming is your friend.

2) Suppose you need 2048 bytes and remote host sends a byte every 5 seconds. You've just hung for 10K seconds = 3 hours. Is that what you want?

I would use alarm 5 and $SIG{ALRM} = sub {$stop = 1;} instead.

3 and 4) From my experience, just read() while select() does the job but I can't give a sure answer here.

like image 140
Dallaylaen Avatar answered Dec 25 '22 12:12

Dallaylaen