Si se especifica la opción Listen en el constructor de IO::Socket::INET el socket creado es un socket para 'escucha', esto es, se asume el lado del servidor.
bash-2.05a$ uname -a Linux manis 2.4.20-37.7.legacysmp #1 SMP Mon Sep 27 21:38:15 EDT 2004 i686 unknown bash-2.05a$ cat -n server.pl 1 #!/usr/local/bin/perl -w 2 use strict; 3 use IO::Socket; 4 5 $SIG{CHLD} = sub { wait(); }; 6 7 my $host = shift || 'localhost'; 8 my $port = shift || 1024; 9 10 my $mains =IO::Socket::INET->new( 11 LocalHost => $host, 12 LocalPort => $port, 13 Listen => 10, 14 Proto => 'tcp', 15 Reuse => 1, 16 ); 17 die "Can't create socket $!\n" unless $mains;El método accept es únicamente válido cuando se llama a un socket en modo escucha (construido con la opción listen ). Obtiene la siguiente conexión de la cola y retorna la sesión conectada al socket. Esta sesión es un socket manejador que se utilizará para conectar con la máquina remota. El nuevo socket hereda todo los atributos de su padre y además está conectado.
Cuando se llama a accept en un contexto escalar retorna el socket conectado. Cuando se llama en un contexto de lista retorna una lista con dos elementos, el primero de los cuales es el socket conectado y el segundo es la dirección empaquetada del host remoto. También es posible obtener esta información haciendo uso del método peername .
18 my $news; 19 while (1) { 20 while ($news = $mains->accept()) { 21 my $pid = fork() and next; 22 23 print "**********************\n"; 24 my $buf = ''; 25 my $c = 1; 26 while (sysread($news, $buf, 1024)) { 27 print "'$buf'\n"; 28 syswrite($news, "message $c from $host"); 29 $c++; 30 } 31 exit(0); 32 } 33 } 34 close($mains);Aquí hacemos un
fork
por cada cliente que se conecta.
El proceso hijo queda a la espera de mensajes de la máquina
remota hasta que esta cierra el canal.
Cuando no se especifica Listen y el tipo del socket es SOCK_STREAM
(que se deduce del protocolo usado)
el método connect es invocado.
-bash-2.05b$ uname -a Linux millo.etsii.ull.es 2.4.22-1.2188.nptlsmp #1 SMP Wed Apr 21 20:12:56 EDT 2004 i686 i686 i386 GNU/Linux -bash-2.05b$ cat -n client.pl 1 #!/usr/local/bin/perl -w 2 use strict; 3 use IO::Socket; 4 5 my $server = shift || 'manis'; 6 my $port = shift || 1234; 7 8 my $host = $ENV{HOSTNAME}; 9 my $sock = IO::Socket::INET->new( 10 PeerAddr => $server, 11 PeerPort => $port, 12 Proto => 'tcp', 13 ); 14 die "Can't create socket $!\n" unless $sock; 15 16 for (1..10) { 17 syswrite($sock,"Message $_ from $host"); 18 my $answer = ''; 19 sysread($sock, $answer,1024); 20 print "'$answer'\n"; 21 } 22 close($sock);
Una alternativa a close
es el método shutdown :
$return_val = $socket->shutdown($how)Cerrará el socket incluso si existen copias en procesos hijos creados con
fork
.
El argumento $how
controla que mitad del socket bidireccional será cerrada.
Valor | Descripción |
0 | Cierra el socket para lectura |
1 | Cierra el socket para escritura |
2 | Cierra el socket totalmente |
Cliente en millo | Servidor en manis |
-bash-2.05b$ ./client.pl manis 1234 'message 1 from manis' 'message 2 from manis' 'message 3 from manis' 'message 4 from manis' 'message 5 from manis' 'message 6 from manis' 'message 7 from manis' 'message 8 from manis' 'message 9 from manis' 'message 10 from manis' -bash-2.05b$ |
bash-2.05a$ ./server.pl manis 1234 ********************** 'Message 1 from millo.etsii.ull.es' 'Message 2 from millo.etsii.ull.es' 'Message 3 from millo.etsii.ull.es' 'Message 4 from millo.etsii.ull.es' 'Message 5 from millo.etsii.ull.es' 'Message 6 from millo.etsii.ull.es' 'Message 7 from millo.etsii.ull.es' 'Message 8 from millo.etsii.ull.es' 'Message 9 from millo.etsii.ull.es' 'Message 10 from millo.etsii.ull.es' |
También es posible usar los métodos recv y send para la comunicación:
bash-2.05a$ cat -n server.pl 1 #!/usr/local/bin/perl -w 2 use strict; 3 use IO::Socket; 4 5 $SIG{CHLD} = sub { wait(); }; 6 7 my $host = shift || 'localhost'; 8 my $port = shift || 1024; 9 10 my $mains =IO::Socket::INET->new( 11 LocalHost => $host, 12 LocalPort => $port, 13 Listen => 10, 14 Proto => 'tcp', 15 Reuse => 1, 16 ); 17 die "Can't create socket $!\n" unless $mains; 18 my $news; 19 while (1) { 20 while ($news = $mains->accept()) { 21 my $pid = fork() and next; 22 23 print "**********************\n"; 24 my $buf = ''; 25 my $c = 1; !26 { !27 $news->recv($buf, 1024); !28 last unless $buf; !29 print "'$buf'\n"; !30 $news->send("message $c from $host"); !31 $c++; !32 redo; !33 } 34 exit(0); 35 } 36 } 37 close($mains);
El método send tiene la sintáxis:
$bytes = $sock->send($data [,$flags, $destination])Envía
$data
a la dirección especificada en $destination
.
En caso de éxito retorna el número de bytes enviados.
Si falla retorna undef
.
El argumento flag es un or
de estas opciones
Opción | Descripcción |
MSG_OOB |
Transmite un byte de datos urgentes |
MSG_DONTROUTE |
Sáltese las tablas de rutas |
El formato de recv es:
$address = $socket->recv($buffer, $length [,$flags])
Acepta $length
bytes desde el socket y los coloca en $buffer
.
Los flags tienen el mismo significado que para send
.
En caso de éxito recv
retorna la dirección empaquetada
del socket del transmisor. En caso de error retorna undef
y la variable
$!
contiene el código de error apropiado.
Realmetne, cuando se usa TCP el método recv
se comporta como sysread
excepto que retorna la dirección del par. Realmente cuando se aprecia la diferencia
es en la recepción de datagramas con el protocolo UDP.