Как сделать правильную обработку ошибок ввода-вывода :: Select? - PullRequest
5 голосов
/ 27 января 2011

Я просматриваю документы и инструкции по правильному использованию IO :: Select с точки зрения сетевых сокетов. Я думаю, что моя голова обернута вокруг большей части.

Тем не менее, я все еще не совсем уверен в правильной обработке ошибок. Скажем, у меня есть нечто похожее на следующий код, работающий внутри объекта. Да, я понимаю, что это грязно, я должен интегрировать IO :: Select в объект, а не в сам сокет fh, я не должен воссоздавать IO :: Select каждый раз в цикле, я перебираю то, что только когда-либо быть единичным возвращаемым дескриптором файла и т. д. Однако это делает пример простым.

Это просто клиент, подключающийся к серверу, но я хочу, чтобы он мог правильно обрабатывать ошибки сетевого уровня, такие как потеря пакетов.

Редактировать: $self->sock() возвращает только открытый сокет IO :: Socket :: INET.

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;
}
  • Нужно ли проверять возврат из recv, или ошибки, которые могут повлиять на него, будут обнаруживаться в объекте IO :: Select?
  • Правильно ли я обращаюсь с таймаутами или неправильно настроена логика?
  • IO :: Socket упоминает об исключении, существующем в дескрипторе файла сокета, для внешних ошибок и других проблем. Должен ли я проверить это в случае тайм-аута? Как? Или это неважно и нормально игнорировать?
  • Существуют ли другие случаи исключений, которые я должен обрабатывать для правильного поведения?

1 Ответ

1 голос
/ 27 января 2011

1) Я бы проверил на всякий случай.Когда дело доходит до выбора (2), защитное программирование - ваш друг.

2) Предположим, вам нужно 2048 байт, и удаленный хост отправляет байт каждые 5 секунд.Вы просто зависли на 10K секунд = 3 часа.Это то, что вы хотите?

Я бы использовал alarm 5 и $SIG{ALRM} = sub {$stop = 1;}.

3 и 4) Исходя из моего опыта, просто read() while select() выполняет свою работу, но я не могу дать здесь верный ответ

...