如何在不阻止Perl的情况下测试STDIN?

时间:2020-03-05 18:40:14  来源:igfitidea点击:

我正在编写我的第一个Perl应用程序-一个与Arduino微控制器对话的AOL Instant Messenger机器人,该机器人又控制一个伺服器,该伺服器将按下sysadmin服务器上的电源按钮,该服务器每28个小时左右随机冻结。

我已经完成了所有艰苦的工作,我只是想添加最后一点代码来打破主循环,并在用户键入"退出"时退出AIM。

问题是,如果我尝试从主程序循环中的STDIN读取数据,它将阻塞该过程,直到输入了输入,这实际上使该bot处于非活动状态。在阅读之前,我尝试过测试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";
  }
}