我正在编写我的第一个 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::选择 只要 STDOUT 关闭,例如当管道中的上游进程退出或输入来自文件时,就可以正常工作。但是,如果输出正在进行(例如来自“tail -f”),则缓冲的任何部分数据 <STDIN> 将不会显示。相反,使用无缓冲 系统读取:

#!/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);
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top