Página 1 de 2

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

NotaPublicado: 2006-08-22 18:18 @804
por kondenado
Bueno, tengo el siguiente problema, espero me puedan ayudar.

Estoy creando un script que se conecta a un puerto y recibe constantemente información del servidor. Hasta el momento puedo recibir la información y procesarla, pero también quiero enviar información aunque sin dejar de recibir.
Es algo así cómo un chat, estar esperando en todo momento la información (imprimiéndole en pantalla) y poder enviar en cualquier momento info hacia el server. La gracia es hacerlo en modo consola y con un solo script.

¿Será posible?

NotaPublicado: 2006-08-22 18:28 @811
por explorer
Utilizando el sistema de búsqueda de este foro me han salido unos cuantos resultados.

Aquí hay uno interesante:
viewtopic.php?t=935

NotaPublicado: 2006-08-23 18:43 @821
por kondenado
Tal vez me expliqué mal, eso no es lo que yo busco. Lo que necesito es un script al cual pueda enviar y recibir información paralelamente e ingresada por el usuario por <STDIN>, pero en el mismo script, algo así como:

Código: Seleccionar todo
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 que quiero hacer un chat:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
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
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

NotaPublicado: 2006-08-23 19:38 @860
por explorer
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.

NotaPublicado: 2006-08-26 19:06 @837
por kondenado
He leído el paper (muy bueno por cierto) pero no he encontrado solución a lo que busco. Lo explicaré de la siguiente manera:

Servidor:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
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);
                  }
            }
       }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Cliente:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
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);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Este código 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 cada dos segundos. Con 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á incluso si pasan un millón 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.

NotaPublicado: 2006-08-26 20:49 @909
por explorer
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.

NotaPublicado: 2006-08-27 07:47 @366
por AkonD
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)

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
   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;
            }
        }
    }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


salu2

NotaPublicado: 2006-08-27 09:57 @456
por explorer
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.

NotaPublicado: 2006-08-27 14:56 @664
por AkonD
Cierto, sorry no lei el post entero, le dejo un ejemplo rapido :P
Código: Seleccionar todo
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

NotaPublicado: 2006-08-27 17:18 @762
por kondenado
He probado el uso de fork y me ha funcionado :D , 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 escribiste:Cierto, sorry no lei el post entero, le dejo un ejemplo rapido :P
Código: Seleccionar todo
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