Un Ejemplo con Coro::Event y Coro::Util

El módulo Coro::Event provee facilidades para la gestión de eventos con una filosofía similar a la de Event, pero de manera que sea compatible con el manejo de corutinas. La principal diferencia está en que no se especifica una función de callback. El programa deberá crear las corutinas necesarias y después llamar a Coro::Event::loop .

Ejecución

El siguiente ejemplo resuelve los nombres de una subred dada:

pp2@nereida:~/src/perl/coro$ event.pl
network (DDD.DDD.DDD) | quit> 213.246.239
NETWORK 213.246.239:
 213.246.239.43 => mail.bopsys.be
 213.246.239.58 => mail.keyware.com
213.246.239.236 => mail.anl-plastics.be
network (DDD.DDD.DDD) | quit> q
pp2@nereida:~/src/perl/coro$

El Programa

pp2@nereida:~/src/perl/coro$ cat -n event.pl
 1  #!/usr/bin/perl
 2  use warnings;
 3  use strict;
 4
 5  use Coro;
 6  use Socket;
 7  use Coro::Event;
 8  use Coro::Util;
 9  use Coro::Debug;
10
11  sub dns {
12     my $network = shift;
13
14     my @pid;
15     for my $x (1..255) {
16       my $coro;
17       push @pid, $coro = async {
18         my $addr = "$network.$x";
19         my $name = scalar(gethostbyaddr(inet_aton($addr), AF_INET));
20         return  unless $name;
21
22         #print "$addr => $name\n";
23         terminate [ $addr => $name ];
24       };
25       $coro->desc("dns of $network.$x");
26     }
27     #Coro::Debug::command('ps');
28     return @pid;
29  }
30
31  my $stdin = Coro::Handle->new_from_fh(\*STDIN);
32
33  local $SIG{PIPE} = 'IGNORE';
34
35  STDOUT->autoflush(1);
36  while() {
37     print "network (DDD.DDD.DDD) | quit> ";
38     my $net = <$stdin>;  # before this line #w is undef
39     chomp $net;
40
41     if ($net =~ /^\d+\.\d+\.\d+$/) {
42        my @pids = dns($net);
43
44        # Watch the coroutines
45        #Coro::Debug::session(\*STDOUT);
46        #Coro::Debug::command('ps');
47
48        # Synchronize, collect and output results
49        my @results;
50        push @results, $_->join for @pids;
51
52        print "NETWORK $net:\n";
53        printf("%15s => %s\n", @$_) for @results;
54
55     } elsif ($net =~ /qu?i?t?/) {
56       exit;
57     } elsif ($net !~ /^\s*$/) {
58       print "unknown command '$net', either 'dns' or 'quit'\n";
59     }
60  }

Ejercicio 5.6.1   En el programa event.pl anterior descomente las llamadas a funciones de Coro::Debug. Lea la documentación del módulo Coro::Debug.

Descomentar la llamada a session nos permitirá ejecutar comandos de depuración interactivamente:

pp2@nereida:~/src/perl/coro$ event.pl
network (DDD.DDD.DDD) | quit> 87.30.69
coro debug session. use help for more info

> ps
                 PID SS  RSS USES Description              Where
           136064756 US  18k    2 [main::]                 [./event.pl:45]
           136064900 -- 1388  168 [coro manager]           [/usr/local/lib/perl/5.8.8/Coro.pm:177]
           136065140 N-   52    0 [unblock_sub scheduler]  -
           136974144 -- 1420  170 [Event idle process]     [/usr/local/lib/perl/5.8.8/Coro/Event.pm:211]
           138396120 -- 2008    2 dns of 87.30.69.157      [./event.pl:19]
           138396876 -- 2008    2 dns of 87.30.69.160      [./event.pl:19]
           138397128 -- 2008    2 dns of 87.30.69.161      [./event.pl:19]
           138398136 -- 2008    2 dns of 87.30.69.165      [./event.pl:19]
           ......... -- ....    2 dns of ............      [./event.pl:19]
           ......... -- 1816    1 dns of ............      [./event.pl:19]
           138496856 -- 1816    1 dns of 87.30.69.255      [./event.pl:19]
>

La función inet_aton

La función inet_aton toma una dirección IP con notación de punto y la empaqueta:

lhp@nereida:~/Lperl/src/perl_networking/ch3$ cat -n name_trans.pl
 1  #!/usr/bin/perl
 2  use strict;
 3  use Socket;
 4  my $ADDR_PAT = /^\d+\.\d+\.\d+\.\d+$/;
 5
 6  while (<>) {
 7    chomp;
 8    die "$_: Not a valid address" unless /$ADDR_PAT/o;
 9    my $name = gethostbyaddr(inet_aton($_),AF_INET);
10    $name ||= '?';
11    print "$_ => $name\n";
12  }

La función gethostbyaddr

En un contexto escalar la función gethostbyaddr devuelve el nombre lógico que se corresponden con la dirección IP empaquetada. Si la búsqueda fracasa devuelve undef. Toma dos argumentos: la dirección empaquetada y la familia de direcciones (habitualmente AF_INET).

En un contexto de lista devuelve cinco elementos:

 DB<1> use Socket
 DB<2> x gethostbyaddr(inet_aton('209.85.135.103'), AF_INET)
0  'mu-in-f103.google.com'  # Nombre Canonico
1  ''                       # lista de alias
2  2                        # Tipo AF_INET
3  4                        # Longitud de la dirección
4  'ÑUg'                    # Dirección empaquetada

El Módulo Coro::Util

Coro::Util sobreescribe las funciones gethostbyname , gethostbyaddr y inet_aton haciendolas no bloqueantes.



Subsecciones
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