Mar Ago 22, 2006 5:18 pm
|
 |
kondenado
Perlero Nuevo

|
Registrado: 21 Ago 2006
Mensajes: 32
|
|
| Enviar y recibir información a través de IO::socket |
|
|
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? |
|
|
|
Mar Ago 22, 2006 5:28 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
|
|
|
|

Mie Ago 23, 2006 5:43 pm
|
 |
kondenado
Perlero Nuevo

|
Registrado: 21 Ago 2006
Mensajes: 32
|
|
|
|
|
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
|
|
|

Mie Ago 23, 2006 6:38 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
|
|
|
|
|
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. |
|

Sab Ago 26, 2006 6:06 pm
|
 |
kondenado
Perlero Nuevo

|
Registrado: 21 Ago 2006
Mensajes: 32
|
|
|
|
|
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. |
|

Sab Ago 26, 2006 7:49 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
|
|
|
|
|
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. |
|

Dom Ago 27, 2006 6:47 am
|
 |
AkonD
Perlero Nuevo

|
Registrado: 06 Oct 2005
Mensajes: 50
Ubicación: España
|
|
|
|
|
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 |
|

Dom Ago 27, 2006 8:57 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
|
|
|
|
|
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. |
|
Dom Ago 27, 2006 1:56 pm
|
 |
AkonD
Perlero Nuevo

|
Registrado: 06 Oct 2005
Mensajes: 50
Ubicación: España
|
|
|
|
|
Cierto, sorry no lei el post entero, le dejo un ejemplo rapido
| 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 |
|
Dom Ago 27, 2006 4:18 pm
|
 |
kondenado
Perlero Nuevo

|
Registrado: 21 Ago 2006
Mensajes: 32
|
|
|
|
|
He probado el uso de fork y me ha funcionado , 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
| 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 |
|
|

Lun Ago 28, 2006 9:22 am
|
 |
AkonD
Perlero Nuevo

|
Registrado: 06 Oct 2005
Mensajes: 50
Ubicación: España
|
|
|
|
|
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 |
|

Lun Ago 28, 2006 10:01 am
|
 |
Perl user
Maestro Honorario

|
Registrado: 03 Nov 2004
Mensajes: 385
|
|
|
|
|
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, |
|

Powered by phpBB © 2001, 2005 phpBB Group
|