Я пишу свое первое приложение Perl - бот AOL Instant Messenger, который общается с микроконтроллером Arduino, который, в свою очередь, управляет сервоприводом, который нажимает кнопку питания на сервере нашего системного администратора, который случайным образом зависает каждые 28 часов или около того.
Я выполнил всю сложную работу, я просто пытаюсь добавить последний фрагмент кода, чтобы прервать основной цикл и выйти из AIM, когда пользователь вводит «выйти».
Проблема в том, что если я пытаюсь читать из STDIN в основном цикле программы, он блокирует процесс до тех пор, пока не будет введен ввод, по существу делая бота неактивным. Я пробовал тестировать EOF перед чтением, но без кубиков ... EOF всегда возвращает false.
Вот пример кода, с которым я работаю:
while(1) {
$oscar->do_one_loop();
# Poll to see if any arduino data is coming in over serial port
my $char = $port->lookfor();
# If we get data from arduino, then print it
if ($char) {
print "" . $char ;
}
# reading STDIN blocks until input is received... AAARG!
my $a = <STDIN>;
print $a;
if ($a eq "exit" || $a eq "quit" || $a eq 'c' || $a eq 'q') {last;}
}
print "Signing off... ";
$oscar->signoff();
print "Done\n";
print "Closing serial port... ";
$port->close() || warn "close failed";
print "Done\n";





Встроенный Perl - это select(), который является сквозным для системного вызова select(), но для здравомыслящих людей я рекомендую IO::Select.
Пример кода:
#!/usr/bin/perl
use IO::Select;
$s = IO::Select->new();
$s->add(\*STDIN);
while (++$i) {
print "Hiya $i!\n";
sleep(5);
if ($s->can_read(.5)) {
chomp($foo = <STDIN>);
print "Got '$foo' from STDIN\n";
}
}
На самом деле IO::Select и select() в целом на Windows работают для (некоторых) сокетов интернет-домена, но только это. Windows - это поразительно сломанная платформа, поэтому не ожидайте, что такой простой кроссплатформенный API будет работать на ней во всех случаях. Вы должны сделать одно для сокетов, другое для файлов / именованных каналов, третье для анонимных каналов / «консольных» дескрипторов и т. д. Тот факт, что они назвали свой poll()WPAPoll, заставил его работать только для интернет-сокетов и отказался исправить известные ошибки в нем, потому что "poll () не рекомендуется" должно быть предупреждением для держись подальше.
Я обнаружил, что IO :: Выбрать работает нормально, пока STDOUT закрывается, например, когда вышестоящий процесс в конвейере завершается или ввод осуществляется из файла. Однако, если вывод продолжается (например, от "tail -f"), то любые частичные данные, буферизованные <STDIN>, отображаться не будут. Вместо этого используйте небуферизованный sysread:
#!/usr/bin/perl
use IO::Select;
$s = IO::Select->new(\*STDIN);
while (++$i) {
if ($s->can_read(2)) {
last unless defined($foo=get_unbuf_line());
print "Got '$foo'\n";
}
}
sub get_unbuf_line {
my $line = "";
while (sysread(STDIN, my $nextbyte, 1)) {
return $line if $nextbyte eq "\n";
$line .= $nextbyte;
}
return(undef);
}
Важное примечание для всех,
IO::Selectработает только в UNIX, не работает в Windows!