2012-09-28 1 views
3

J'essaie de communiquer avec un processus interactif. Je veux que mon script perl soit un "moddle man" entre l'utilisateur et le processus. Le processus met le texte à stdout, invite l'utilisateur à une commande, met plus de texte à stdout, invite l'utilisateur à une commande, ....... Un graphique primitive est fourni:Perl bidirectionnel IPC de tuyau, comment éviter la mise en mémoire tampon de sortie

User <----STDOUT---- interface.pl <-----STDOUT--- Process 
User -----STDIN----> interface.pl ------STDIN---> Process 
User <----STDOUT---- interface.pl <-----STDOUT--- Process 
User -----STDIN----> interface.pl ------STDIN---> Process 
User <----STDOUT---- interface.pl <-----STDOUT--- Process 
User -----STDIN----> interface.pl ------STDIN---> Process 

Les Simule suivants ce que j'essaie de faire:

#!/usr/bin/perl 

    use strict; 
    use warnings; 

    use FileHandle; 
    use IPC::Open2; 
    my $pid = open2(\*READER, \*WRITER, "cat -n"); 
    WRITER->autoflush(); # default here, actually 
    my $got = ""; 
    my $input = " "; 

    while ($input ne "") { 
      chomp($input = <STDIN>); 
      print WRITER "$input \n"; 
      $got = <READER>; 
      print $got; 
    } 

Du fait de la mise en mémoire tampon de sortie, l'exemple ci-dessus ne fonctionne pas. Quel que soit le texte tapé ou le nombre d'entrées pressées, le programme se trouve juste là. La façon de le fixer est d'émettre:

my $pid = open2(\*READER, \*WRITER, "cat -un"); 

avis « -UN de chat » par opposition à un « cat -n ». -u désactive la bufferisation de sortie sur cat. Lorsque la mise en mémoire tampon de sortie est désactivée, cela fonctionne. Le processus que j'essaie d'interagir avec les buffers les plus probables est le suivant car je suis confronté aux mêmes problèmes avec "cat -n". Malheureusement, je ne peux pas désactiver la mise en mémoire tampon de sortie sur le processus avec lequel je communique, alors comment gérer ce problème?

Update1 (en utilisant ptty):

#!/usr/bin/perl 

    use strict; 
    use warnings; 

    use IO::Pty; 
    use IPC::Open2; 

    my $reader = new IO::Pty; 
    my $writer = new IO::Pty; 

    my $pid = open2($reader, $writer, "cat -n"); 
    my $got = ""; 
    my $input = " "; 

    $writer->autoflush(1); 

    while ($input ne "") { 
      chomp($input = <STDIN>); 
      $writer->print("$input \n"); 
      $got = $reader->getline; 
      print $got; 
    } 

~

+0

'open2' ouvre toujours ses propres tuyaux, vous ne pouvez pas donner Ptyś. Voir http://www.perlmonks.org/?node_id=835953 pour un exemple simple qui utilise 'IO :: Pty :: Easy'. – Barmar

Répondre

6

Il existe trois types de tampon:

  1. mise en mémoire tampon de bloc: La sortie est placé dans un tampon de taille fixe. Le tampon est vidé lorsqu'il devient plein. Vous verrez la sortie sortir en morceaux.
  2. Mise en mémoire tampon de ligne: la sortie est placée dans un tampon de taille fixe. Le tampon est vidé quand un retour à la ligne est ajouté au tampon et quand il devient plein.
  3. Pas de mise en mémoire tampon: la sortie est transmise directement au système d'exploitation.

En Perl, fonctionne tampon comme suit:

  • poignées de fichier sont mises en mémoire tampon par défaut. Une exception: STDERR n'est pas mis en mémoire tampon par défaut.
  • La mise en mémoire tampon de bloc est utilisée. Une exception: STDOUT est une ligne tamponnée si et seulement si elle est connectée à un terminal.
  • La lecture à partir de STDIN vide le tampon pour STDOUT.
  • Jusqu'à récemment, Perl utilisait des tampons de 4 Ko. Maintenant, la valeur par défaut est 8 Ko, mais cela peut être changé quand Perl est construit.

Ces deux premiers sont étonnamment standard dans toutes les applications. Cela signifie:

  • User -------> interface.pl

    L'utilisateur est une personne. Il ne tampon pas par exemple, mais c'est une source de données très lente.OK

  • interface.pl ----> Process

    sortie du bloc interface.pl est tamponnée. BAD

    fixe par adjonction, à interface.pl:

    use IO::Handle qw(); 
    WRITER->autoflush(1); 
    
  • Process ----> interface.pl

    la sortie du bloc processus est tamponnée. BAD

    fixe en ajoutant ce qui suit à Process:

    use IO::Handle qw(); 
    STDOUT->autoflush(1); 
    

    Maintenant, vous allez probablement me dire que vous ne pouvez pas modifier la méthode. Si oui, cela vous laisse trois options:

    • Utilisez une ligne de commande ou une option de configuration fournie par l'outil pour modifier son comportement de mise en mémoire tampon. Je ne connais aucun outil offrant une telle option.
    • Tromper l'enfant pour utiliser la mise en mémoire tampon de ligne au lieu de la mise en mémoire tampon de bloc en utilisant un pseudo tty au lieu d'un canal.
    • Quitter.

  • interface.pl -------> User

    sortie de interface.pl est un tampon de ligne. OK (droit?)

+0

Merci pour l'explication très détaillée. J'ai été googling et vu beaucoup d'explications discutant en utilisant un ptty. Les exemples et même le cPan doc on ptty sont très ambigus. Je n'ai pas encore incorporé vos suggestions, mais avant de lire ceci, j'ai "converti" mon code pour utiliser ptty mais cela ne fonctionne toujours pas. Pourriez-vous me dire si je «fais bien» ou me donner un exemple en utilisant mon code ci-dessus. – user974896

+0

Je vais regarder dans IO :: Pty :: Easy. Je me demandais quel est le problème avec la mise en mémoire tampon des blocs? Pourquoi le processus reste-t-il assis plutôt que d'envoyer le bloc? Je m'en fous si ça revient ligne par ligne ou en bloc. Êtes-vous en train de sous-entendre que les tuyaux sont intrinsèquement tamponnés en blocs? Si oui, pourquoi "awk '{print $ 2}' | df -h | grep" SOMETHING "fonctionne-t-il? Pourquoi ne pas les bloquer en raison de la mise en mémoire tampon? – user974896

+0

Le seul problème est que vous avez dit que vous ne le vouliez pas. Ils ne sont pas là à ne pas envoyer, ils restent là à attendre l'entrée // Non, ce sont les programmes qui tamponnent // 'df' ne se bloque pas en attente de saisie car' df' ne prend aucune entrée. vous avez dit, 'grep' est en attente d'une entrée (puisque la sortie de' df' est sûrement bloquée, mais 'df' se termine très rapidement, donc' grep 'ne pèse que pour un clin d'oeil – ikegami

Questions connexes