Question

J'écris ma première application Perl - un robot AOL Instant Messenger qui communique avec un microcontrôleur Arduino, qui à son tour contrôle un servo qui appuiera sur le bouton d'alimentation du serveur de notre administrateur système, qui se bloque de manière aléatoire toutes les 28 heures environ.

J'ai fait tout le travail difficile, j'essaie juste d'ajouter un dernier morceau de code pour briser la boucle principale et me déconnecter d'AIM lorsque l'utilisateur tape « quitter ».

Le problème est que si j'essaie de lire depuis STDIN dans la boucle principale du programme, cela bloque le processus jusqu'à ce que l'entrée soit saisie, rendant essentiellement le bot inactif.J'ai essayé de tester EOF avant de lire, mais pas de dés...EOF renvoie toujours false.

Voici ci-dessous un exemple de code avec lequel je travaille :

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";
Était-ce utile?

La solution

Le Perl intégré est select(), qui est un intermédiaire vers le select() appel système, mais pour les personnes sensées je recommande IO::Select.

Exemple de code :

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

Autres conseils

Je l'ai trouvé IO : Sélectionner fonctionne correctement tant que STDOUT est fermé, par exemple lorsque le processus en amont du pipeline se termine ou que l'entrée provient d'un fichier.Cependant, si la sortie est en cours (comme depuis "tail -f") alors toutes les données partielles mises en mémoire tampon par <STDIN> ne sera pas affiché.Utilisez plutôt le mode sans tampon lecture système:

#!/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);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top