• Publicidad

Dos sockets con IO::Select

Así que programas sin strict y las expresiones regulares son otro modo de hablar. Aquí encontrarás respuestas de nivel avanzado, no recomendable para los débiles de corazón.

Dos sockets con IO::Select

Notapor perleando_apenas » 2009-05-28 12:23 @557

Hola a todos nuevamente.

Les cuento que quiero hacer una pequeña prueba para un módulo de mayor tamaño. Mi objetivo es hacer un único programita en Perl que abra dos [iyz]sockets[/iyz] distintos en un mismo [iyz]host[/iyz] y quede escuchando en ambos... y bueno, poder discriminar por cual de los dos entró un mensaje.

El código que estoy probando lo tomé prestado de otra respuesta en este mismo foro y es:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl -w

use IO::Socket;
use IO::Select;
use strict;

my $srv_sock = IO::Socket::INET->new (
                                 Hostname => "192.168.1.2",
                                 LocalPort => "9999",
                                 Proto => 'udp'
                                 ) or die "socket: $@";

my $rqt_sock = IO::Socket::INET->new (
                                 Hostname => "192.168.1.2",
                                 LocalPort => "9998",
                                 Proto => 'udp'
                                 ) or die "socket: $@";

my $selector = new IO::Select ( $srv_sock, $rqt_sock );

while (my @ready = $selector->can_read ) {
  foreach ( @ready ) {
    ( $_ == $srv_sock ) ? print "server\n" : print "request\n";
  }
}
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Cuando ejecuto este código se queda esperando. Luego, desde otra ventana mando mensaje al puerto 9999 o 9998, con un código en Perl como este:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$sock = IO::Socket::INET->new(Proto     => 'udp',
                              PeerPort  => $portno,
                              PeerAddr  => "192.168.1.2")
    or die "Creating socket: $!\n";

$sock->send($msg) or die "send: $!";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


El problema es que si mando al 9999 el [iyz]server[/iyz] se va en un [iyz]loop[/iyz] imprimiendo repetidamente:

Código: Seleccionar todo
server
server
server
...


Y por supuesto... si mando al 9998, el [iyz]loop[/iyz] se va infinitamente con:

Código: Seleccionar todo
request
request
request
...


¿Por qué pasa esto?

La verdad es que estos son mis primeros intentos con IO::Select... así que agradeceré mucho la ayuda que me puedan dar.

Salu2!
perleando_apenas
Perlero nuevo
Perlero nuevo
 
Mensajes: 20
Registrado: 2009-04-17 10:27 @477

Publicidad

Notapor explorer » 2009-05-28 18:59 @832

Entra en un bucle sin fin porque te está indicando que hay algo por leer, pero que no estás leyendo.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

use IO::Socket;
use IO::Select;

my $srv_sock = IO::Socket::INET->new (
     Hostname  => 'localhost',
     LocalPort => '9999',
     Proto     => 'udp',
 ) or die "socket: $@";

my $rqt_sock = IO::Socket::INET->new (
     Hostname  => 'localhost',
     LocalPort => '9998',
     Proto     => 'udp',
 ) or die "socket: $@";

my $selector = new IO::Select ( $srv_sock, $rqt_sock );

$|=1; # no caché

while (my @ready = $selector->can_read ) {
    foreach my $fh ( @ready ) {

        print "Abriendo...\n";
        my $destino = ( $fh == $srv_sock ) ? 'Server' : 'Request';
        if (defined (my $buf = <$fh>)) {
            print "$destino: $buf";
        }
        print "Cerrando...\n";

    }
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Última edición por explorer el 2009-05-29 17:09 @756, editado 3 veces en total
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Algo no anda bien ...

Notapor perleando_apenas » 2009-05-29 09:10 @423

Gracias Explorer por tu respuesta.

Probé el código que enviaste. Lo ejecuto y se queda esperando. Cuando envío algo por el puerto 9999 o 9998 imprime "Abriendo..." y se queda pegado ... no hace nada más. ¿No debería imprimir Server o Request según el puerto por donde entre un mensaje?

Por otro lado, me gustaría entender bien qué significa esta asignación:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$buf = <$fh>
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Muchas gracias.
perleando_apenas
Perlero nuevo
Perlero nuevo
 
Mensajes: 20
Registrado: 2009-04-17 10:27 @477

Notapor explorer » 2009-05-29 13:40 @611

El ejemplo que te he puesto es muy simple... se queda esperando a que haya algo qué leer y, a continuación, lee una línea (una cadena de bytes terminadas en un retorno de carro), que es justo la línea de código que muestras.

Si se queda esperando es porque no le estás enviando ese retorno de carro.

Si estás intercambiando datos binarios de un formato conocido, pero que no son líneas de texto, entonces deberás usar las funciones de lectura como read() para indicar cuánto debe de leer.
Última edición por explorer el 2009-05-29 16:29 @728, editado 1 vez en total
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

¡Ahora sí que sí!

Notapor perleando_apenas » 2009-05-29 16:28 @728

Efectivamente, explorer, tienes razón.
Agregué un "\n" al "mensaje" que envío al socket y lo imprime correctamente. También se da cuenta sin problemas desde qué puerto está recibiendo la entrada.
¡Te agradezco mucho tu ayuda!
perleando_apenas
Perlero nuevo
Perlero nuevo
 
Mensajes: 20
Registrado: 2009-04-17 10:27 @477

Funciones de lectura?

Notapor perleando_apenas » 2009-06-01 18:20 @805

Hola nuevamente.

explorer escribiste:....
Si estás intercambiando datos binarios de un formato conocido, pero que no son líneas de texto, entonces deberás usar las funciones de lectura como read() para indicar cuánto debe de leer.


Respecto de los datos que recibirá el puerto, se trata de paquetes snmp del tipo "GET" que deberán ser parseados y respondidos por mi programita. Estoy usando un cliente para generar gets desde otro equipo hasta un puerto X en el host donde estoy desarrollando y por supuesto ya no puedo usar aquello de agregar un "\n" para que el paquete sea correctamente detectado.

Así que tengo que ver el tema de las funciones de lectura que mencionaste. El problema es que no sé a cuáles estás haciendo referencia. Imagino que te refieres a algo como lo que aparece aquí http://www.perlfect.com/articles/perlfile.shtml, pero no sé cómo incluirlo en el ciclo while.

Gracias por tu ayuda.

Muchas gracias.
perleando_apenas
Perlero nuevo
Perlero nuevo
 
Mensajes: 20
Registrado: 2009-04-17 10:27 @477

Ya más en limpio ...

Notapor perleando_apenas » 2009-06-02 12:53 @578

Hola.
Creo haberme aclarado un poco más respecto al tema de la lectura de los sockets definidos.

Mi código va así más o menos:


Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my $alarm_sock = IO::Socket::INET->new (
                                 Hostname => $SRV_HOST,
                                 LocalPort => $SRV_PORT,
                                 Proto => 'udp'
                                 ) or die "socket: $@";
print "Awaiting UDP messages (alarms) on port $SRV_PORT\n";

my $get_sock = IO::Socket::INET->new (
                                 Hostname => $SRV_HOST,
                                 LocalPort => $GET_PORT,
                                 Proto => 'udp'
                                 ) or die "socket: $@";
print "Awaiting UDP messages (gets) on port $GET_PORT\n";

my $selector = new IO::Select ( $alarm_sock, $get_sock );
$|=1; #no flush

while (my @ready = $selector->can_read ) {
  foreach my $fh ( @ready ) {
    $fh->recv(my $buf, $MAXLEN);

    if ( $buf eq "stop\n" ) {
      print "Ending UDP server ...\n";
      close($alarm_sock);
      close($get_sock);
      exit 0;
    }

    if ( $fh == $alarm_sock ) {
      alarm_received ( $buf );
    }
    else {
      get_received ( $buf );
    }
  }
}
close($alarm_sock);
close($get_sock);
 
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Como expliqué antes, mi idea es tener un objeto "IO::Select" donde hay definidos 2 sockets. Por un socket entrarán alarmas y por otro entrarán solicitudes de estado SNMP del tipo "get" que deberé parsear (esa es una etapa en la que aún no entro).

Según esta descripción me sería de mucha ayuda que pudieran hacer observaciones de mi código... que está recibiendo correctamente... pero tal vez ustedes tienen ideas para hacerlo más eficiente (las funciones que estoy llamando no están aún completamente definidas... pero por ahora no es importante).

Saludos y gracias.
perleando_apenas
Perlero nuevo
Perlero nuevo
 
Mensajes: 20
Registrado: 2009-04-17 10:27 @477

Notapor explorer » 2009-06-07 12:17 @554

Aquí lo bonito sería usar POE...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

...

Notapor perleando_apenas » 2009-06-09 14:14 @635

AUCH!
Sería ideal probar algo nuevo, lamentablemente el tiempo no lo permite. Lo tendré en cuenta cuando retome una nueva versión del agente.
En todo caso, ¿por qué consideras recomendable usar POE?
perleando_apenas
Perlero nuevo
Perlero nuevo
 
Mensajes: 20
Registrado: 2009-04-17 10:27 @477

Notapor explorer » 2009-06-09 14:27 @644

Multitarea.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Avanzado

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados