如何在Perl中测试STDIN而不会阻塞?

14

我正在编写我的第一个Perl应用程序——一个AOL即时通讯机器人,它与Arduino微控制器进行通信,后者又控制着伺服电机,以便按下我们系统管理员服务器上的电源按钮,该服务器大约每28个小时就会随机冻结。

我已经完成了所有困难的部分,现在只是想添加最后一段代码,以便在用户输入“quit”时中断主循环并注销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";
2个回答

21

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";
  }
}

7
提示:IO::Select仅适用于UNIX系统,不适用于Windows! - slm
3
实际上,在Windows上,IO::Selectselect()通常适用于(某些)Internet域套接字,但仅限于此。Windows是一个极其不稳定的平台,因此不要指望这样一个简单的跨平台API在所有情况下都能正常工作。对于套接字,您必须做一件事情,对于文件/命名管道,您必须做另一件事情,对于匿名管道/“控制台”句柄等等... 他们将自己的poll()称为WPAPoll,只使它适用于Internet套接字,并拒绝修复其中已知的错误,因为“poll()已被弃用”,这应该是一个警告,要远离它。 - alexchandel

3

我发现只要STDOUT关闭(例如在管道中的上游进程退出或输入来自文件),IO::Select 就能正常工作。然而,如果输出是持续的(例如来自“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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接