Un Ejemplo con Lecturas sin Bloqueo

Como se comentó anteriormente el buen funcionamiento de las comunicaciones bidireccionales con aplicaciones externas no se puede garantizar. Podemos evitar atascos - como se hizo en el ejemplo anterior - poniendo un límite al tiempo de espera en la lectura. Otra estrategia que ayuda es usar funciones de lectura y escritura sin buffers y no esperar por líneas completas terminadas en \n (véase la sección 1.7). Aún mejor, podemos hacer lecturas sin bloqueo.

En el ejemplo usamos open2 para poner en marcha el depurador gdb haciendo que ejecute un cierto número de comandos bajo el control de nuestra aplicación y retornar posteriormente el control al usuario. Cuando ejecute este ejemplo observará una falta de sincronía entre la escritura de sus comandos y la respuesta del depurador. Es preciso añadir un retorno de carro adicional para lograr ver el resultado de nuestro último comando. Para lograr un control mas adecuado es mejor hacer uso de una herramienta que provea de terminales virtuales como Expect (seccion 8.1).

En la línea 35 indicamos que las lecturas desde $RDR se hacen en forma no bloqueante. El método blocking esta definido en IO::Handle . La función readgdb muestra la forma de leer desde un manejador sin bloqueo. La función sysread devuelve undef si no hay nada disponible. En tal caso la variable $! contiene el código de error EWOULDBLOCK (definida en POSIX). Esta situación no debe confundirse con la devolución de un cero, la cual indica la presencia del final de fichero.

El manejo de escrituras sin bloqueo es similar. El retorno de un valor undef señala la imposibilidad de escribir. Si la escritura sólo se ha podido hacer parcialmente es responsabilidad del programador intentarlo posteriormente.

lhp@nereida:~/Lperl/src/perl_networking/ch2$ cat -n open2gdb_1.pl
 1  #!/usr/bin/perl -w
 2  use strict;
 3  use IPC::Open2;
 4  use IO::Handle;
 5  use POSIX;
 6  use constant BUFFERSIZE => 2048;
 7
 8  my $WTR = IO::Handle->new();
 9  my $RDR = IO::Handle->new();
10
11  # Lectura sin bloqueo  
12  # 0 es EOF; undef es "no hay cadena"
13  sub readgdb {
14    my $line = '';
15    my $bytes = sysread($RDR, $line, BUFFERSIZE);
16    if (defined($bytes)) {
17      return "$line" if ($bytes);
18      exit 0; # EOF from gdb
19    }
20    return "Press <CR>: " if ($! == EWOULDBLOCK);
21    die "sysread error: $!";
22  }
23
24  my $init = <<"EOI";
25  set args 0 1000000 4
26  b main
27  l
28  R
29  n
30
31  EOI
32
33  $init .= "n\n"x5; # 5 next
34  my $pid = open2($RDR, $WTR, 'gdb pi');
35  $RDR->blocking(0);
36  print readgdb();
37  my $bytes = syswrite($WTR, $init);
38  print readgdb();
39  while (<>) {
40    my $bytes = syswrite($WTR, $_);
41    print readgdb();
42  }
43  wait;

Casiano Rodríguez León
Licencia de Creative Commons
Programación Distribuida y Mejora del Rendimiento
por Casiano Rodríguez León is licensed under a Creative Commons Reconocimiento 3.0 Unported License.

Permissions beyond the scope of this license may be available at http://campusvirtual.ull.es/ocw/course/view.php?id=44.
2012-06-19