Perl en Español

  1. Home
  2. Tutoriales
  3. Foro
  4. Artículos
  5. Donativos
  6. Publicidad
 

Enviar y recibir información a través de IO::socket

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Intermedio
Mensaje Mar Ago 22, 2006 5:18 pm
kondenado
Perlero Nuevo
Perlero Nuevo
Registrado: 21 Ago 2006
Mensajes: 32
Enviar y recibir información a través de IO::socket Responder citando

Bueno, tengo el siguiente problema, espero me puedan ayudar.

Estoy kreando un script ke se konecta a un puerto y recibe konstantemente información del servidor. Hasta el momento puedo recibir la información y procesarla, pero tb kiero enviar información aunke sin dejar de recibir.
Es algo así kmo un chat, estar esperando en todo momento la información (imprimiendola en pantalla) y poder enviar en kualkier momento info hacia el server. La gracia es hacerlo en modo konsola y kon un solo script.

¿Será posible?
Mensaje Mar Ago 22, 2006 5:28 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
Responder citando

Utilizando el sistema de búsqueda de este foro me han salido unos cuantos resultados.

Aquí hay uno interesante:
http://perlenespanol.baboonsoftware.com/foro/viewtopic.php?t=935
Mensaje Mie Ago 23, 2006 5:43 pm
kondenado
Perlero Nuevo
Perlero Nuevo
Registrado: 21 Ago 2006
Mensajes: 32
Responder citando

Tal véz me explike mal, eso no es lo ke yo busko. Lo ke necesito es un script al kual pueda enviar y recibir información paralelamente e ingresada por el usuario por <STDIN>, pero en el mismo script, algo así kmo:

Código:
información proveniente del server
información proveniente del server
información proveniente del server
write: información a enviar


Para entender mejor la analogía pensemos ke kiero hacer un chat

Código:

use strict;
use IO::Socket;

my $sock = IO::Socket::INET->new( PeerAddr => "host.com",
                                                 Port => 1111,
                                                 Proto => 'tcp') || die "$!\n";

while (<$sock>)
          {
             print $_;
           }
# hast aki todo bien, pero al mismo tiempo ke el script esta
# recibiendo a todo momento la info proveniente del server, me gustaría
# saber si se puede tener un prompt para poder ir enviando

Mensaje Mie Ago 23, 2006 6:38 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
Responder citando

Yo aprendí leyendo esta página:
http://www.linuxjournal.com/article/3237

Aunque te recomiendo una lectura completa, lo que necesitas está a partir del ejemplo nº5, con un ejemplo de comunicación bidireccional entre servidor y cliente. Y ejemplos más adelante muestran cómo enviar comandos desde el cliente al servidor leyéndolos desde la entrada estándar.
Mensaje Sab Ago 26, 2006 6:06 pm
kondenado
Perlero Nuevo
Perlero Nuevo
Registrado: 21 Ago 2006
Mensajes: 32
Responder citando

He leído el paper (muy bueno por cierto) pero no he enkontrado solución a lo ke busko. Lo explicare de la siguiente manera:

Servidor:
Código:
use strict;
use IO::Socket;

my($sock, $accept, $count);

$sock = IO::Socket::INET->new( LocalPort => 10001,
                               Proto => 'tcp',
                               Listen => 6,
                               Reuse => 1) || die "Socket problem $!\n";

if ($sock)
    {
     $accept = $sock->accept();
     while ($accept)
            {
              sleep 2;
              print $accept "Hola $count\n";
              $count++;
              if ($count == 5)
                  {
                    shutdown($accept,2);
                    exit(1);
                  }
            }
       }


Cliente:
Código:

use strict;
use IO::Socket;

my($sock, $in, $msg);

$sock = IO::Socket::INET->new( PeerAddr => "127.0.0.1",
                               PeerPort => 10001,
                               Proto => 'tcp') || die "Socket problem $!\n";

while ($in = <$sock>)
       {
         print $in;
         print "write: ";
         chomp ($msg = <STDIN>);
         print $sock $msg;
        }

shutdown($sock,2);


Este kode funciona de lo más bien, pero... al momento de conectar el cliente al servidor, recibirá la info mandada por el server ("Hola $count"), lo que en teoría debería llegar al cliente kada dos segundos. Kon el cliente recibimos la info y después el script nos pregunta por info para mandar al server, pero si no introducimos info en <STDIN>, la info del server no nos llegará inkluso si pasan un millon de segundos, ya que el script está a la espera de info ingresada por el user. Por lo tanto, mi objetivo es saber si hay alguna manera de evitar eso, imprimiendo la info en pantalla cada dos segundos sin importar si el cliente ha ingresado o no la info.
Mensaje Sab Ago 26, 2006 7:49 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
Responder citando

La respuesta entonces es haciendo un fork en el lado del cliente. Un hilo se encargará de hablar con el server, y el otro de hablar con el usuario.
En el mismo enlace, en el ejemplo nº7 (A forking Client), lo tienes.
Mensaje Dom Ago 27, 2006 6:47 am
AkonD
Perlero Nuevo
Perlero Nuevo
Registrado: 06 Oct 2005
Mensajes: 50
Ubicación: España
Responder citando

Lo puedes hacer de 3 maneras

1- Usando fork (lo cual creara un subproceso por cada cliente)
2- Usando IO::Select;
3- Usando thread;

Yo te recomiendo que uses IO::Select

Un simple ejemplo de IO::Select i sockets.. (sacado de google)

Código:

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

    $lsn = new IO::Socket::INET(Listen => 1, LocalPort => 8080);
    $sel = new IO::Select( $lsn );
   
    while(@ready = $sel->can_read) {
        foreach $fh (@ready) {
            if($fh == $lsn) {
                # Create a new socket
                $new = $lsn->accept;
                $sel->add($new);
            }
            else {
                # Process socket

                # Maybe we have finished with the socket
                $sel->remove($fh);
                $fh->close;
            }
        }
    }


salu2
Mensaje Dom Ago 27, 2006 8:57 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
Responder citando

AkonD, el ejemplo que has puesto está sacado de la página de manual de IO::Select, y se refiere a cómo hacer un server que crea nuevos sockets.
En cambio, lo que kondenado pedía era del lado del cliente, para atender tanto lo que le llega desde el servidor como del usuario.
Mensaje Dom Ago 27, 2006 1:56 pm
AkonD
Perlero Nuevo
Perlero Nuevo
Registrado: 06 Oct 2005
Mensajes: 50
Ubicación: España
Responder citando

Cierto, sorry no lei el post entero, le dejo un ejemplo rapido Razz
Código:

my $select = IO::Select->new($socket,\*STDIN);
while (my @ready = $select->can_read) {
  foreach (@ready) {
    if ($_ eq \*STDIN) {
      lectura_stdin(\*STDIN);
    } else {
      lectura_socket($_);
    }
  }
}


salu2
Mensaje Dom Ago 27, 2006 4:18 pm
kondenado
Perlero Nuevo
Perlero Nuevo
Registrado: 21 Ago 2006
Mensajes: 32
Responder citando

He probado el uso de fork y me ha funcionado Very Happy , ya kon anterioridad había usado fork, pero no tenía idea ke kon el ejemplo explikado en akel paper podía lograr lo ke buskaba.

Por cierto, no he entendido el ejemplo ke dio AkonD:

AkonD escribió:
Cierto, sorry no lei el post entero, le dejo un ejemplo rapido Razz
Código:

my $select = IO::Select->new($socket,\*STDIN);
while (my @ready = $select->can_read) {
  foreach (@ready) {
    if ($_ eq \*STDIN) {
      lectura_stdin(\*STDIN);
    } else {
      lectura_socket($_);
    }
  }
}


salu2
Mensaje Lun Ago 28, 2006 9:22 am
AkonD
Perlero Nuevo
Perlero Nuevo
Registrado: 06 Oct 2005
Mensajes: 50
Ubicación: España
Responder citando

Lo que se hace en este ejemplo es leer el socket y el STDIN con el módulo IO::Select sin tener que usar fork. Al recorrer el array que genera $select->can_read comprueba si se trata del STDIN o el socket y lanza la función lectura_stdin o lectura_socket según corresponda.

Puedes encontrar la documentación del módulo en http://search.cpan.org/author/GBARR/IO-1.2301/IO/Select.pm
Mensaje Lun Ago 28, 2006 10:01 am
Perl user
Maestro Honorario
Maestro Honorario
Registrado: 03 Nov 2004
Mensajes: 385
Responder citando

En realidad select(2) y su implementación en Perl hacen mas qué solo retornarte eso.

La syscall select es una llamada bloqueante la cual te permite "inspeccionar" file descriptors ( en Perl, te permite inspeccionar file handlers ). Ahora siguiente el ejemplo de Perl, una vez teniendo la lista de FH's a inspeccionar, select espera que el kernel le indique que uno de ellos está listo para leer/escribir o con una condición excepcional.

Esta técnica es muy utilizada para servidores de alto rendimiento en conjunto con Threading o Forking servers, puesto que en vez de estar revisando esos FH's manualmente con un poll, el sistema lo hace por tí. Una vez teniendo cual FH vas a atender, normalmente un thread o un proceso diferente, puede manejar la conexiòn hacia él.

Es interesante ver todas las opciones que tienes para hacer I/O sobre streams ( como sockets ), pero una de las mas eficientes en cuanto a la cantidad de conexiones a atender es esta, es decir, la unión de Multiplexed I/O( o sea el uso de select ), y threads o forks.

Saludos,
Publicar nuevo tema   Responder al tema    Foros de discusión -> Intermedio Todas las horas son GMT - 6 Horas
Página 1 de 1



Powered by phpBB © 2001, 2005 phpBB Group