Чтение STDIN с тайм-аутом

Пример сценария для проверки состояния ваших интерфейсов с помощью команды pingс использованием параметра -I, рекомендованного @Raman Sailopal в его комментарии:

for i in $( ls /sys/class/net )
do 
    ping -c1 -I $i 8.8.8.8 >> /dev/null 2>&1
    if [ $? -eq 0 ]
then 
    echo Your $i interface is connected   
else
    echo Your $i interface is disconnected    
    fi
done

1
28.12.2019, 10:19
2 ответа

Некоторые проблемы:

  • Параметр O_NONBLOCKвлияет на описание открытого файла, а не только на дескриптор файла. Например, если вы запустите that-script; cat, вы увидите cat: -: Resource temporarily unavailable, так как catstdin стал неблокирующим -
  • Если вы используете неблокирующий ввод-вывод -, системный вызов read()возвращает ошибку EAGAIN, если в данный момент нет ввода и установлен eof. perleof()вызывает read()и подразумевает буферизованный ввод-вывод. Вы не можете использовать его для неблокирующего ввода-вывода -. В вашем примере первый block1читается в eof(), затем select()ждет в течение sleep 1, а второй block1читается в read(), который возвращает оба block1с.

Здесь вам лучше использовать блокирующий ввод-вывод и использовать alarm(), например, для тайм-аута. Если вы используете неблокирующий ввод-вывод -и select(), не используйте eof()и используйте sysread()вместо read()и убедитесь, что вы сбросили флаг O_NONBLOCKпри выходе, если он был установлен заранее (по-прежнему плохая идея устанавливать O_NONBLOCKна стандартный ввод, так как этот стандартный ввод может использоваться совместно с другими процессами ).

1
27.01.2020, 23:40

Следуя предложениям Стефана, я придумал это, и пока, кажется, оно работает.

#!/usr/bin/perl -w                                                                                                                                   

use strict;

my $timeout = 2;
my $buf = "";
my $blocksize = 30;
my $readsize;
my $nread;
my $buflen;
my $alarm;
my $eof;

open(my $in, "<&", "STDIN") or die;

do {
    eval {
        local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required                                                                                  
        alarm $timeout;
        # Add upto the next full block                                                                                                               
        $readsize = $blocksize - (length $buf) % $blocksize;
        do {
            $nread = sysread $in, $buf, $readsize, length $buf;
            $readsize -= $nread;
        } while($nread and $readsize);
        alarm 0;
    };
    if ($@) {
        die unless $@ eq "alarm\n";   # propagate unexpected errors                                                                                  
        $alarm = 1;
    } else {
        $alarm = 0;
    }
    print "B:$buf<\n";
    $buf = "";
    $eof = not ($nread or $alarm);
} while(not $eof);
0
27.01.2020, 23:40

Теги

Похожие вопросы