2008-08-18 13 views
11

Ich schreibe meine erste Perl-App - ein AOL Instant Messenger-Bot, der mit einem Arduino-Mikrocontroller kommuniziert, der seinerseits einen Servo steuert, der den Power-Button auf dem Server unseres Systemadministrators drückt, der alle 28 Stunden zufallsartig zufriert.Wie kann ich STDIN testen, ohne in Perl zu blockieren?

Ich habe all die harten Sachen erledigt, ich versuche nur ein letztes Bit Code hinzuzufügen, um die Hauptschleife zu unterbrechen und mich vom AIM abzumelden, wenn der Benutzer 'quit' tippt.

Das Problem ist, wenn ich versuche, von STDIN in der Hauptprogrammschleife zu lesen, blockiert es den Prozess, bis Eingabe eingegeben wird, den Bot praktisch inaktiv machend. Ich habe versucht, vor dem Lesen für EOF zu testen, aber keine Würfel ... EOF gibt immer nur falsch zurück.

Hier unten ist, ist ein Beispielcode Ich arbeite mit:

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

Antwort

17

Die Perl eingebaute in select() ist, die eine Durchgang ist zum select() Systemaufruf, aber für vernünftig Leute, die ich empfehle IO::Select .

Codebeispiel:

#!/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"; 
    } 
} 
+4

Big Anmerkung zu jemand anderem, 'IO :: Select' nur auf UNIX arbeitet, funktioniert nicht auf Windows! – slm

+0

Eigentlich 'IO :: Select' und' select() 'im Allgemeinen unter Windows funktioniert für (einige) Internet-Domain-Sockets, aber nur das. Windows ist eine erstaunlich zerbrochene Plattform. Erwarten Sie also nicht, dass eine so einfache plattformübergreifende API für alle Fälle darauf funktioniert. Sie müssen eine Sache für Sockets machen, eine andere für Dateien/Named Pipes, eine andere für anonyme Pipes/"Console" Handles, etc ... Die Tatsache, dass sie ihre 'poll()' 'WPAPoll' aufgerufen haben, hat es nur für Internet-Sockets, und weigern sich, bekannte Bugs darin zu beheben, weil "poll() veraltet ist" sollte eine Warnung an ** bleiben weit weg **. – alexchandel