$sudo apt-get install xinetd
$ sudo nano echo
# default: off
# description: An xinetd internal service which echo's characters back to
# clients.
# This is the tcp version.
service echo
{
disable = no
type = INTERNAL
id = echo-stream
socket_type = stream
protocol = tcp
user = root
wait = no
}
#
This is the udp version.
service echo
{
disable = yes
type = INTERNAL
id = echo-dgram
service echo
{
disable = yes
type = INTERNAL
id = echo-dgram
socket_type = dgram
protocol = udp
user = root
wait = yes
}
protocol = udp
user = root
wait = yes
}
$ sudo
netstat -putan|grep xine
tcp 0 0 0.0.0.0:7 0.0.0.0:* ESCUCHAR 3583/xinetd
tcp 0 0 0.0.0.0:7 0.0.0.0:* ESCUCHAR 3583/xinetd
$ telnet
localhost 7
Escribo string y este me lo repite
Escribo string y este me lo repite
Abro nuevos telnets de la
misma forma en terminales distintos y hace lo mismo. Escribo string y me lo
contesta repitiéndolo.
Si este telnet lo hago al
puerto 80, este esperará una petición asiciado a su protocolo, espera una
petición web.
Telnet es mi vehículo
para conectar con el servidor, por lo tanto se usa en la parte cliente.
$ sudo
netstat -putan|grep xin
Telnet a la linea que das agrega \r\n. Si escribimos papa,
al pulsar intro, nos devuelve papa\r\n.
1º - Telnet envía agregando siempre \r\n
2º - flush buffers cuando usamos funciones librerías para escribir
en un stream(canal)
buferring es en la memoria del servidor, al escribir lo descarga, mientras que unbuffering es en memoria del PC
buferring es en la memoria del servidor, al escribir lo descarga, mientras que unbuffering es en memoria del PC
xinetd sirve para ahorrar recursos.
Si tengo 3, o 5 o 10
servicios esperando peticiones, significa que tengo 3, 5, o 10 procesos o
demonios escuchando y esperando petición.
Con xinetd puedo tener la
misma funcionalidad, pero con un unico servidor en memoria. Estará previamente
configurado para esperar las peticiones de varios programas.
Cuando recibe una
petición, por ejemplo de correo, este levanta el servidor de correo para
atenderlo.
Echo es un claro ejemplo de como un servidor atiende varias
peticiones iniciando un nuevo proceso. Pero nuestros códigos socket comienza un
proceso, lo atiende y acaba. Cada proceso que comienza un servidor sería igual
que el funcionamiento del socket.
Podríamos variar mi
programa para que cuando el cliente lo llama, no se lo de este y acabe, sino
que este cree un nuevo proceso, le atienda y acabe dicho proceso, pero mi
programa sigue escuchando.
Un nuevo proceso, o un
nuevo hilo.
Especificaciones de la ACTIVIDAD:
•
#Escribir un servidor de
echo con puerto 7777
•
#prueba con telnet \r\n
•
#Recordar flush
•
#Acaba cuando el cliente
envia "fin"
•
#Acaba el server con el
string 99
CLIENTE
1: echo telnet - use IO::Socket::UNIX;
#!/usr/bin/perl
use IO::Socket::UNIX;
#uso libreria socket UNIX = socket local
#!/usr/bin/perl
use IO::Socket::UNIX;
#uso libreria socket UNIX = socket local
my $socket = IO::Socket::UNIX->new(
Type => SOCK_STREAM,
Peer => '/tmp/mysocket',
);
die "Can't create socket: $!" unless $socket;
#SE ESTABLECE LA CONEXIÓN CON EL SERVIDOR
#Si la conexión del socket da error, termina
Type => SOCK_STREAM,
Peer => '/tmp/mysocket',
);
die "Can't create socket: $!" unless $socket;
#SE ESTABLECE LA CONEXIÓN CON EL SERVIDOR
#Si la conexión del socket da error, termina
$socket->autoflush;
while()
{
#Mientras se escriba entradas por
teclado,...
print $socket $_;
#Envia al servidor por SOCKET estas entradas
print $socket $_;
#Envia al servidor por SOCKET estas entradas
if(my $line=<$socket>) {
#Si se guarda en variable lo que trae el canal desde el servidor, ...
print $line;
#Imprime esta variable
#Si se guarda en variable lo que trae el canal desde el servidor, ...
print $line;
#Imprime esta variable
my
$salir="fin";
#Guardo en variable string salir
#Guardo en variable string salir
if ($line =~ $salir) {
#Si en la variable se guarda el string salir, ...
#Si en la variable se guarda el string salir, ...
close
$socket;
#Cierra canal socket
#Cierra canal socket
exit();
#Salir
}
}
}
#Salir
}
}
}
SERVIDOR
1: echo telnet - use IO::Socket::UNIX;
#!/usr/bin/perl -w
use IO::Socket::UNIX;
#uso libreria socket UNIX = socket local
#!/usr/bin/perl -w
use IO::Socket::UNIX;
#uso libreria socket UNIX = socket local
my $socket_path = '/tmp/mysocket';
unlink $socket_path if -e $socket_path;
unlink $socket_path if -e $socket_path;
my $socket = IO::Socket::UNIX->new(
Local => $socket_path,
Type => SOCK_STREAM,
Listen => SOMAXCONN,
);
die "Can't create socket: $!" unless $socket;
#Si la conexión del socket da error, termina
Local => $socket_path,
Type => SOCK_STREAM,
Listen => SOMAXCONN,
);
die "Can't create socket: $!" unless $socket;
#Si la conexión del socket da error, termina
while (1) {
#Se crea un bucle infinido. Significa que si queremos salir deberemos poner un exit().
#Se crea un bucle infinido. Significa que si queremos salir deberemos poner un exit().
my
$connection = $socket->accept;
#ACEPTO LA CONEXIÓN
# se crea el tunel de conexión.
#ACEPTO LA CONEXIÓN
# se crea el tunel de conexión.
$connection->autoflush(1);
while
(my $line = <$connection>) {
#Mientras se guarde en variable lo que manda el cliente por el SOCKET
#Mientras se guarde en variable lo que manda el cliente por el SOCKET
chomp($line);
$nueva="$line" . "\n";
print $connection $nueva;
#MANDA al CLIENTE por SOCKET la variable
$nueva="$line" . "\n";
print $connection $nueva;
#MANDA al CLIENTE por SOCKET la variable
my $salir="fin";
#En variable guarda string fin
if ($line =~ $salir){
#Si lo que manda cliente es salir, ...
print "99\n";
#Imprime por pantalla 99
#Si lo que manda cliente es salir, ...
print "99\n";
#Imprime por pantalla 99
exit();
#Sale del programa
}
}
}
#Sale del programa
}
}
}
CLIENTE 2:
echo telnet - use Socket;
#!/usr/bin/perl
#!/usr/bin/perl
use Socket;
use IO::Handle;
use IO::Handle;
socket(S,PF_INET,SOCK_STREAM,6);
$dest=sockaddr_in(7777,inet_aton('127.0.0.1')) ;
$paddr = connect(S, $dest);
$dest=sockaddr_in(7777,inet_aton('127.0.0.1')) ;
$paddr = connect(S, $dest);
S->autoflush;
while() {
print S $_;
print S $_;
if($line=)
{
print $line;
}
else { last; }
}
print $line;
}
else { last; }
}
close S;
SERVIDOR 2: echo telnet - use Socket;
#!/usr/bin/perl
#!/usr/bin/perl
use Socket;
socket (Server, PF_INET, SOCK_STREAM, 6) || die
("socket");
$pbind = sockaddr_in(7777,INADDR_ANY) || die ("sockaddr_in");
bind(Server,$pbind) || die ("bind");
listen(Server,SOMAXCONN) || die ("listen");
$pbind = sockaddr_in(7777,INADDR_ANY) || die ("sockaddr_in");
bind(Server,$pbind) || die ("bind");
listen(Server,SOMAXCONN) || die ("listen");
my $connection;
while ($connection = accept(Client, Server)) {
($port,$iaddr) = sockaddr_in($connection);
($port,$iaddr) = sockaddr_in($connection);
$name =
gethostbyaddr($iaddr,AF_INET);
print "Atiendo petición desde puerto
", $port, " de máquina ",$name, " dirección
",inet_ntoa($iaddr),"\n";
Server->autoflush;
while (my
$line=) {
chomp($line);
$nueva="$line" . "\n";
print $nueva;
}
print "99\n";
}
chomp($line);
$nueva="$line" .
print $nueva;
}
print "99\n";
}
Especificaciones de la ACTIVIDAD:
Un cliente que permita conversar con un servidor.
Pensar, aquí en el cliente hay poca variación, la adaptación viene en el SERVIDOR.
Pasaríamos de tener un servidor de echo a un servidor talk.
El usuario que opera el SERVIDOR lee lo que recibe el servidor y escribe una respuesta, por teclado claro. Esto es lo que no hace tu servidor de echo
Pensar, aquí en el cliente hay poca variación, la adaptación viene en el SERVIDOR.
Pasaríamos de tener un servidor de echo a un servidor talk.
El usuario que opera el SERVIDOR lee lo que recibe el servidor y escribe una respuesta, por teclado claro. Esto es lo que no hace tu servidor de echo
CLIENTE 2:
talk
#!/usr/bin/perl -W
use IO::Socket;
#!/usr/bin/perl -W
use IO::Socket;
$host=;
$port=;
$cliente =
IO::Socket::INET->new(
Proto => 'tcp',
PeerAddr => $host,
PeerPort => $port,
Reuse => 1,
) || die print "Error, no se pudo conectar al servidor :(";
Proto => 'tcp',
PeerAddr => $host,
PeerPort => $port,
Reuse => 1,
) || die print "Error, no se pudo conectar al servidor :(";
print
"Se conecto correctamente :)\n";
while
($cliente) {
print "->";
$msg=;
print "Enviaste:$msg";
$cliente->send($msg);
$serv=<$cliente>;
print "Servidor:$serv";
}
close $cliente;
print "->";
$msg=
print "Enviaste:$msg";
$cliente->send($msg);
$serv=<$cliente>;
print "Servidor:$serv";
}
close $cliente;
SERVIDOR 2:
echo telnet - use Socket;
#!/usr/bin/perl -W
use IO::Socket;
#!/usr/bin/perl -W
use IO::Socket;
$port=;
$server=IO::Socket::INET->new(
PeerAddr => 127.0.0.1,
LocalPort => $port,
Listen => 1,
Reuse => 1,
)|| die "Error no se pudo crear el servidor";
PeerAddr => 127.0.0.1,
LocalPort => $port,
Listen => 1,
Reuse => 1,
)|| die "Error no se pudo crear el servidor";
print
"Servidor Corriendo, esperando a cliente...\n";
while ($conexion = $server->accept() ) {
print "Conectado:",inet_ntoa((unpack_sockaddr_in(getpeername $conexion))[1])," \n";
print "Conectado:",inet_ntoa((unpack_sockaddr_in(getpeername $conexion))[1])," \n";
while ($conexion) {
$msg=<$conexion>;
print "Cliente: $msg";
print "->";$env=;
print "Enviaste:$env";
$conexion->send($env) || die "No se pudo enviar el mensaje.Por favor reinicie el servidor";
}
$msg=<$conexion>;
print "Cliente: $msg";
print "->";$env=
print "Enviaste:$env";
$conexion->send($env) || die "No se pudo enviar el mensaje.Por favor reinicie el servidor";
}
}
close($conexion);
close($conexion);
Los servidores no suelen
responder a la conexión del cliente, es decir, suele llamar el cliente y el
servidor no le suele contestar “que quieres” ni nada similar.
Cuando se conecta el
cliente al servidor, este crea algo similar a un Open de File. Abrir un socket
es el equivalente a un Open.
Leer
FILE:
#!/usr/bin/perl
open(FILE,"
@source = ;
foreach $linea (@source){
print $linea;
}
close(FILE);
Leer
y Escribir en un FILE:
#!/usr/bin/perl
open(FILE,">archivo.txt");
while ($contador >= 5){
$contador++;
print FILE "Nuestra linea
numero $contador\n";
}
close(FILE);
exit(1);
En socket: connect
(SOCK, $paddr);
Guarda en SOCK , la conexión de dirección y puerto de esta conexión.
Guarda en SOCK , la conexión de dirección y puerto de esta conexión.
En file: open(FILE,"
Guarda en FILE, el contenido del fichero.
Guarda en FILE, el contenido del fichero.
En
el SERVIDOR:
Cuando el servidor hace la aceptación de la conexión (accept), este es bloqueante.
Un servidor siempre tiene un bucle, esperando la conexión.
Cuando el servidor hace la aceptación de la conexión (accept), este es bloqueante.
Un servidor siempre tiene un bucle, esperando la conexión.
while(1) es igual que
while(accept(Z,S))
while() Mientras
fluye el accept, es un read
Ahora el servidor bloquea el canal y espera leer del cliente
while(
Ahora el servidor bloquea el canal y espera leer del cliente
En
el CLIENTE:
connect(S, …)
while()
print S
print S
print S
connect(S, …)
while()
print S
print S
print S
IPC
mediante socket:
El bucle de interacción
es el que puede variar según protocolo.
Server Cliente
connect while(accept){
while(){ while(){
while(){ while(){
IO
funcion librería call system en perl
funcion real read → sysread
write → syswrite
funcion real read → sysread
write → syswrite
Las funciones se dividen
en 2, funciones de sistema y funciones de librerías.
Qué
pasa si el canal para la transferencia de datos creado, en el script Servidor,
es cerrado con la función 'close', y el cliente va a ejecutar una lectura.
connect <----------------> accept
escribe al canal <----------------> lee del canal
lee del canal <----------------> escribe al canal
escribe al canal <----------------> lee del canal
---- hasta aquí todo bien, ambos están coordinados ----
lee del canal <----------------> close el canal.---------------->---------------->---------------->---------------->---------------->
escribe al canal <----------------> lee del canal
lee del canal <----------------> escribe al canal
escribe al canal <----------------> lee del canal
---- hasta aquí todo bien, ambos están coordinados ----
lee del canal <----------------> close el canal.---------------->---------------->---------------->---------------->---------------->
Como vemos el cliente
esta ejecutando una lectura (está bloqueado, esperando) mientras que el
Servidor nunca escribirá, ya que lo que hace es cerrar el canal con lo cual 'no
hay más canal'.
En el Servidor está todo bien, podrá ir a recibir una nueva conexión cliente, es decir un nuevo ciclo del bucle.
En el cliente "no están bien las cosas", el kernel reacciona ....
En el Servidor está todo bien, podrá ir a recibir una nueva conexión cliente, es decir un nuevo ciclo del bucle.
En el cliente "no están bien las cosas", el kernel reacciona ....
Si llamamos a close() no
se podrá escribir o leer usando ese socket, y si alguien trata de hacerlo
recibirá un mensaje de error(excepción).
El kernel genera la señal |broken(señal PIPE).
El kernel genera la señal |broken(señal PIPE).
Cuando el servidor cierra
el socket (close()), es END FILE.
Las
señales a los programas los envía los kernels, por ejemplo con kill -9 proceso, en realidad se le está
diciendo al kernel, envía la señal -9 al programa. Las señales siempre son para
procesos.
La señal que se envía al
kernel realiza una acción por defecto, por ejemplo, el CONTROL-C envía también
una señal (kill -2 proceso).
#!/usr/bin/perl
print "Escribe: ";
print "Escribe: ";
while(){
print $_;
print "Escribe: ";
}
#Se corta la entrada de datos(STDIN) con control-D
print $_;
print "Escribe: ";
}
#Se corta la entrada de datos(STDIN) con control-D
#!/usr/bin/perl
open(F, $ARGV[1]) or die "ERROR de apertura de fichero";
open(F, $ARGV[1]) or die "ERROR de apertura de fichero";
while(){
print $_;
}
close F;
#Se corta la entrada de datos
print $_;
}
close F;
#Se corta la entrada de datos
Especificaciones de la ACTIVIDAD:
Definir una
función en el programa cliente que en ningún momento se va a llamar, pero se va
a tener que agregar que equivale a signal (man 2 signal), que indique al kernel
que debe ejecutar.
#!/usr/bin/env perl
$SIG{'INT'} = \&sigIntHandler;
$SIG{'INT'} = \&sigIntHandler;
sleep 100;
sub sigIntHandler {
print "INT caught!\n";
exit;
}
#kill -s SIGINT proceso = kill -2 proceso
print "INT caught!\n";
exit;
}
#kill -s SIGINT proceso = kill -2 proceso
#!/usr/bin/env perl
$SIG{'INT'} = \&sigIntHandler;
$SIG{'INT'} = \&sigIntHandler;
sleep 100;
print hola;
sleep 20;
print "luego del sleep\n\n";
#Este es tu programa
print hola;
sleep 20;
print "luego del sleep\n\n";
#Este es tu programa
sub sigIntHandler {
print "INT caught!\n";
print "NO ME MATAS, JEJEJEJE t!\n";
}
print "INT caught!\n";
print "NO ME MATAS, JEJEJEJE t!\n";
}
#kill -s
SIGINT proceso = kill -2 proceso
#Si se hace CONTROL-C, llama a la función y muestra el print
#La señal -9, -17, -23 no puede ser atrapada
#Si se hace CONTROL-C, llama a la función y muestra el print
#La señal -9, -17, -23 no puede ser atrapada
Socket UDP
El cliente
crea la primera función, función socket
use Socket;
socket (S, ….)
…....
…. Canal creado, etc
…. Trabajo, interactúo con el servidor
…. acabo
…. Trabajo, interactúo con el servidor
…. acabo
Ahora no me
sirve para conectar con un nuevo servidor.
No puede usarse para iniciar y conectar con un servidor distinto una vez terminado con el actual.
ESTO OCURRE EN TCP!!!
Hay que crear de nuevo el socket.
No puede usarse para iniciar y conectar con un servidor distinto una vez terminado con el actual.
ESTO OCURRE EN TCP!!!
Hay que crear de nuevo el socket.
Mientras que
en UDP si te sirve, ...
Como funcionan los servicios:
En los
servicios, existe una conexión del cliente con el servidor, pero luego este
servidor le pasa el “tubo” a un hijo para que pueda este interactuar con el
cliente, mientras el servidor padre siguen en la conexión y a la escucha.
while (1) {
dfClient = accept ( dfServer, puntSockClient, &longClient );
/* acepta la conexion cliente */
dfClient = accept ( dfServer, puntSockClient, &longClient );
/* acepta la conexion cliente */
printf ("\n acepto la conexion
\n");
if ( fork() == 0 ) /* crea hijo y envia
fichero */
{
escribeFichero ( dfClient );
close ( dfClient ); /* cierra el socket */
exit ( 0 );
}else {
close ( dfClient ); /* cierra el descriptor cliente */
} /* en el padre */
}
/*El padre le retorna al hijo 0 y el hijo le retorna al padre su PID*/
{
escribeFichero ( dfClient );
close ( dfClient ); /* cierra el socket */
exit ( 0 );
}else {
close ( dfClient ); /* cierra el descriptor cliente */
} /* en el padre */
}
/*El padre le retorna al hijo 0 y el hijo le retorna al padre su PID*/
$pid = fork();
if( $pid == 0 ){
print "Esto
es un proceso HIJO ",$$,"\n";
sleep 50;
print
"Proceso HIJO acabado\n";
exit 0;
}
print "**Esto
es un proceso PADRE $$ y HIJO y su PID es $pid **\n";
sleep 30;
print
"Proceso PADRE acabado\n";
exit
0;
Comentarios
Publicar un comentario
Si te ha gustado, haz un comentario, ..., GRACIAS