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

12 perl stdin

我正在编写我的第一个Perl应用程序 - 一个与Arduino微控制器对话的AOL Instant Messenger机器人,后者控制一个伺服器,它将按下我们系统管理员服务器上的电源按钮,该服务器每隔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";
Run Code Online (Sandbox Code Playgroud)

jj3*_*j33 19

内置的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";
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 其他任何人都要注意,"IO :: Select"仅适用于UNIX,不适用于Windows! (5认同)
  • 实际上,Windows 上的“IO::Select”和“select()”通常适用于(某些)互联网域套接字,但仅此而已。Windows 是一个极其糟糕的平台,因此不要指望如此简单的跨平台 API 能够适用于其上的所有情况。您必须为套接字做一件事,为文件/命名管道做另一件事,为匿名管道/“控制台”句柄做另一件事,等等......事实上,他们将其称为“poll()”“WPAPoll”,仅使其适用于互联网套接字,并拒绝修复其中的已知错误,因为“poll() 已弃用”应该是**远离**的警告。 (3认同)