• Publicidad

Demonio y servidor

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Demonio y servidor

Notapor davidferrero » 2009-08-18 05:51 @285

Me encuentro con el siguiente problema.

A lo largo del desarrollo de mi programa me he encontrado con diversos problemas que aquí amablemente habéis solucionado; en este momento me encuentro con lo siguiente: una vez que me conformaba con el funcionamiento de mi servidor, se quedaba colgado y no mostraba bien los datos, o no los refrescaba. El caso es que vía telnet la respuesta era precisa.

Resulta que ahora me encuentro con que si lo pongo como demonio me muestra los datos una vez pero no me deja ni refrescar ni nada, es decir, necesito reiniciar el servicio para poder volver a mostrar la página, y el caso es que no encuentro el motivo de mi problema.

Este sería el código del servidor:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #! /usr/bin/perl -w
  2.  
  3. #LIBRERIAS
  4.  
  5. use strict;
  6. use IO::Socket;
  7.  
  8. # Find out where we are, so we can find our required libraries
  9.     my $curr_path = $0;
  10.     $curr_path =~ s/lms\.pl//;  
  11.           require "${curr_path}lib/LinuxMonitoringServer/FUNCTIONS.pl";
  12.           require "${curr_path}lib/LinuxMonitoringServer/MONITOR.pl";
  13.  
  14. #
  15. sub Wait{
  16. wait; #wait needed to keep <defunct> pids from building up
  17. }
  18.  
  19. $SIG{CHLD}=\&Wait;
  20.  
  21. sub server(){
  22.  
  23. my $server = IO::Socket::INET->new(
  24. PeerAddr => inet_ntoa(INADDR_BROADCAST),
  25. LocalPort=>680,
  26. Type=>SOCK_STREAM,
  27. Reuse=>1,
  28. Listen=>10)
  29. or die "$@\n";
  30.  
  31. while (my $client = $server->accept())
  32. {
  33. next if my $pid = fork; die "fork - $!\n" unless defined $pid;
  34. $|=1;
  35. print $client &getHTML();
  36. close($client);
  37. exit(fork);
  38. }
  39. continue
  40. {
  41. close($client)or die "$@\n";
  42. kill CHLD=>-$$ or die "$@\n";
  43. }
  44. } # new
  45. 1;
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


y este otro sería el perteneciente a la creación del demonio:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl -w
  2. # lms.pl - Linux Monitorig Server
  3. # This is the control script that starts and stops the server
  4.  
  5. use strict;
  6.  
  7.  
  8. # Find out where we are, so we can find our required libraries
  9. BEGIN {
  10. my $curr_path = $0;
  11. $curr_path =~ s/lms\.pl//;
  12. eval "require '${curr_path}lib/LinuxMonitoringServer/SERVER.pl';";
  13. die "Error in LMS loading libraries:\n$@"  if ($@);
  14. }
  15.  
  16. my $curr_path = $0;
  17. $curr_path =~ s/lms\.pl//;
  18.  
  19.  
  20. # Set a wait for ending child processes
  21. local $SIG{CHLD} = sub { wait; };
  22.  
  23. # UNIX type machines only:
  24. # This checks to see what arguments we are given, and then
  25. # start or stop the server accordingly.
  26.     if (my $arg = shift(@ARGV)) {
  27.         if ($arg =~ /^start/i) {
  28.             my $pid1 = fork;
  29.             exit(0)  if ($pid1);
  30.             my $pid2 = fork;
  31.             exit(0)  if ($pid2);
  32.             local (*PID);
  33.             if (open(PID,">> ". "$curr_path/pidfile")) {
  34.                 print PID "$$\n";  # Store the pid of the new server process
  35.                 close(PID);
  36.                 print "Starting Linux Monitoring Server...\n";
  37.                 &server();
  38.             } else {
  39.                 print "Error - cannot write to pid file $!";
  40.                 exit(1);
  41.             }
  42.  
  43.         } elsif ($arg =~ /^stop/i) {
  44.             local (*PID);
  45.             if (open(PID,"< ". "$curr_path/pidfile")) {
  46.                 while (my $line = <PID>) {
  47.                     chop($line);
  48.                     if (! kill 9, $line) {
  49.                         print "Cannot kill process $line!\n";
  50.                     } else {
  51.                         print "Killed process $line.\n";
  52.                     }
  53.                 }
  54.                 close(PID);
  55.                 open(PID,"> "."$curr_path/pidfile");
  56.                 close(PID);
  57.             } else {
  58.                 print "Error - cannot read pid file $!";
  59.                 exit(1);
  60.             }
  61.         } elsif ($arg =~ /^restart/i) {
  62.             local (*PID);
  63.             if (open(PID,"< ". "$curr_path/pidfile")) {
  64.                 while (my $line = <PID>) {
  65.                     chop($line);
  66.                     if (! kill 9, $line) {
  67.                         print "Cannot kill process $line!\n";
  68.                     } else {
  69.                         print "Killed process $line.\n";
  70.                     }
  71.                 }
  72.                 close(PID);
  73.                 open(PID,"> ". "$curr_path/pidfile");  # Rewrite the pid file
  74.                 close(PID);
  75.             } else {
  76.                 print "Error - cannot read pid file $!";
  77.             }
  78.             my $pid1 = fork;
  79.             exit(0)  if ($pid1);
  80.             my $pid2 = fork;
  81.             exit(0)  if ($pid2);
  82.             {
  83.                 local (*PID);
  84.                 # Store the pid of the new server process
  85.                 if (open(PID,">> ". "$curr_path/pidfile")) {
  86.                     print PID "$$\n";  
  87.                     close(PID);
  88.                     print "Starting Linux Monitoring Server...\n";
  89.                     &server();
  90.                 } else {
  91.                     print "Error - cannot write to pid file $!";
  92.                     exit(1);
  93.                 }
  94.             }
  95.         }
  96.     }
  97.  
  98. exit(0);
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Seguramente existan imperfecciones en el código, ya que mi conocimiento es muy escaso por lo que toda ayuda para depurarlo se agradece y se siente a la vez.

Gracias por las respuestas.
Última edición por explorer el 2009-08-18 05:57 @290, editado 1 vez en total
Razón: Ortografía
davidferrero
Perlero nuevo
Perlero nuevo
 
Mensajes: 25
Registrado: 2009-07-29 03:12 @175

Publicidad

Re: Demonio y servidor

Notapor netsoul » 2009-08-18 09:14 @426

Disculpa mi ignorancia, como habías dicho en tu post anterior que había supuestamente problemas de compatibilidad al instalar módulos, ¿Podrías colocar algún detalle técnico legible sobre esos supuestos problemas?. De esta manera (al menos creo yo), podríamos matar dos conejos en un solo tiro. ;)
Última edición por explorer el 2009-08-19 06:17 @303, editado 1 vez en total
Razón: Anglicismos
With Perl
Imagination is more important than knowledge. Albert Einstein.
netsoul
Perlero nuevo
Perlero nuevo
 
Mensajes: 150
Registrado: 2008-05-04 01:11 @091

Re: Demonio y servidor

Notapor davidferrero » 2009-08-19 01:15 @094

Como en su momento comento en ese mismo post, y dejando en evidencia mi desconocimiento de Perl, no es la palabra compatibilidad la más adecuada, los posibles problemas los expresó perfectamente explorer. Yo con compatibilidad me refería más bien a que mi intención es crear un sistema el cual pueda se instalado en cualquier máquina Linux con la instalación por defecto de Perl, por lo que la idea de depender de módulos no me satisfacía, aunque lógicamente existen posibilidades de hacerlo sin necesidad de tener que instalar los propios módulos como bien contesto también explorer, por lo cual sería más aproximado el término de portabilidad, para el cual, lógicamente, si es compatible tiene muchas posibilidades de ser portable.
Última edición por explorer el 2009-08-19 06:16 @303, editado 1 vez en total
Razón: Ortografía
davidferrero
Perlero nuevo
Perlero nuevo
 
Mensajes: 25
Registrado: 2009-07-29 03:12 @175

Re: Demonio y servidor

Notapor explorer » 2009-08-19 08:18 @387

En el Perl Cookbook, hay un capítulo entero (el 17, de la segunda edición) completamente dedicado al tema de Sockets, servidores, etc. La receta número 17 se dedica precisamente a cómo crear un servidor como si fuera un demonio:

17.17.1 Problem
You want your program to run as a daemon.

17.17.2 Solution
If you are paranoid and running as root, chroot to a safe directory:
chroot("/var/daemon")
or die "Couldn't chroot to /var/daemon: $!";
Fork once, and let the parent exit:
$pid = fork;
exit if $pid;
die "Couldn't fork: $!" unless defined($pid);
Close the three standard filehandles by reopening them to /dev/null:
for my $handle (*STDIN, *STDOUT, *STDERR) {
open($handle, "+<", "/dev/null")
|| die "can't reopen $handle to /dev/null: $!";
}
Dissociate from the controlling terminal that started us and stop being part of whatever process group we had been a member of:
use POSIX;

POSIX::setsid( )
or die "Can't start a new session: $!";
Trap fatal signals, setting a flag to indicate that we need to gracefully exit:
$time_to_die = 0;

sub signal_handler {
$time_to_die = 1;
}

$SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&signal_handler;
# trap or ignore $SIG{PIPE}
Wrap your actual server code in a loop:
until ($time_to_die) {
# ...
}
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Demonio y servidor

Notapor davidferrero » 2009-08-20 01:24 @100

Gracias por tu respuesta explorer, el único problema que me surge es el hecho de que no la entiendo bien, el motivo de por qué me dices eso, es decir, has visto fallos a la hora de crear el demonio, o es que simplemente no es un buen método para servidores.

Bueno, de todas maneras seguiré mirando, ahora he pasado de nuevo a la idea de HTTP::Daemon, más que nada porque he vuelto a la idea de PerlWebServer pero realizándole las modificaciones a mi antojo, porque me encuentro los mismos problemas pero con el servidor más completo.

Seguramente los errores no pertenezcan solo al propio servidor sino que se junten con problemas del resto de scripts del programa, además de como se gestionan los hijos y de más.

Perdón por mi ignorancia y gracias por las respuestas.
davidferrero
Perlero nuevo
Perlero nuevo
 
Mensajes: 25
Registrado: 2009-07-29 03:12 @175

Re: Demonio y servidor

Notapor explorer » 2009-08-20 03:00 @166

En la receta que te he puesto están descritos los pasos necesarios para crear un demonio:
Traducido:

1.- Si eres paranoico y estás corriendo como root, chroot a un directorio seguro:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
    chroot("/var/daemon")
        or die "Couldn't chroot to /var/daemon: $!";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


2.- fork() una vez, y deja que el padre termine:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
    $pid = fork;
    exit if $pid;
    die "Couldn't fork: $!" unless defined($pid);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


3.- Cierra los tres manejadores de ficheros estándares reabriéndoles hacia /dev/null:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
    for my $handle (*STDIN, *STDOUT, *STDERR) {
        open($handle, "+<", "/dev/null")
            || die "can't reopen $handle to /dev/null: $!";
    }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


4.- Disóciate de la terminal que estás usando que se usó para arrancar y deja de formar parte del grupo de procesos del que fuimos miembros:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
    use POSIX;

    POSIX::setsid( )
        or die "Can't start a new session: $!";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


5.- Atrapa señales fatales, activando una bandera para indicar que necesitamos una forma amable de terminar:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
    $time_to_die = 0;

    sub signal_handler {
        $time_to_die = 1;
    }

    $SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&signal_handler;
    # trap or ignore $SIG{PIPE}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


6.- Cubre tu código actual con un bucle:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
    until ($time_to_die) {
        # ...
    }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

(Luego sigue una explicación larga de estos pasos y por qué)

Como ves, se trata de una serie de reglas para desligar al proceso demonio del que fuera su padre, su grupo de procesos, de la terminal que lo arrancó y de los canales de entrada y salida que su padre le abrió. Luego, capturas las señales fatales para saber cuándo tienes que morir. Y finalmente, el programa entra en un bucle sin fin, atendiendo a sus tareas, hasta que le dicen que se tiene que terminar.

Eso es lo que no he visto en tu código (al menos, de forma clara. Quizás me equivoque).

Quizás pase algo tan sencillo como que el hijo que crea el demonio para atender a las peticiones no cierra la conexión.

En ese caso, quizás tengas que usar shutdown() en lugar de close(), como indica la receta 17.9 (cerrar un socket después de hacer un fork()):

Imagine a server that wants to read its client's request until end-of-file, and then send an answer. If the client calls close, that socket is now invalid for I/O, so no answer would ever come back. Instead, the client should use shutdown to half-close the connection.
que quiere decir:
Imagina un servidor que quiere leer las peticiones de su cliente hasta el fin-del-fichero, y entonces envía una respuesta. Si el cliente llama a close(), este socket es ahora inválido para E/S, así que ninguna respuesta regresará. En lugar de eso, el cliente debería usar shutdown para medio-cerrar la conexión.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Demonio y servidor

Notapor davidferrero » 2009-08-20 03:42 @196

Nuevamente perdón por mi incomprensión y gracias por la respuesta, entendía el código y digamos en cierta manera también el proceso que seguía, el problema es que como siempre existen diferentes maneras de poder hacer las cosas, y sobre todo en lenguajes con tantas posibilidades, pues no entendía si me decías que estaba mal mi código y que le faltaba eso, o que eso era una manera mejor de hacerlo, sea lo que sea, agradezco tu respuesta y revisaré y intentaré modificar dicho código.

Además ahora precisamente tengo el problema de que el servidor refresca correctamente la página y la muestra correctamente, pero lo que ocurre es que el refresco que realiza la propia página es mediante
Sintáxis: [ Descargar ] [ Ocultar ]
Using html4strict Syntax Highlighting
  1.  <META HTTP-EQUIV="refresh" CONTENT="10">
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
aunque es cierto que en ocasiones muestra un comportamiento un tanto irregular y falla también el refresco del propio explorador teniendo que darle dos veces para poder refrescar la página.

El refresco de la página en el caso del código HTML mencionado lo que hace es generar nuevos hijos del servicio, además por duplicado, ¿puede que tenga algo que ver con cómo creo el demonio, no? ¿Alguien entiende este comportamiento del servidor?
Última edición por explorer el 2009-08-20 03:48 @200, editado 1 vez en total
Razón: Ortografía
davidferrero
Perlero nuevo
Perlero nuevo
 
Mensajes: 25
Registrado: 2009-07-29 03:12 @175

Re: Demonio y servidor

Notapor explorer » 2009-08-20 03:50 @201

No entiendo por qué en las líneas 78 y 80 haces dos llamadas fork().
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Demonio y servidor

Notapor davidferrero » 2009-08-20 04:20 @222

Como ya he mencionado la parte del servidor y demonio, es la que estoy modificando del proyecto PerlWebServer, y puesto que mis conocimientos son más bien limitados voy paso a paso intentando entender el código.

No sabría decirte exactamente la función que cubre ese código, pero sí decirte que quitando esas dos líneas el comportamiento varía bastante. Si las quito a la hora de resetear el demonio lo que hace es no ejecutarlo en segundo plano, y quitando solo uno lo ejecuta en segundo plano y aparentemente no da problemas.

Esto es más que nada ensayo, prueba y error. Voy intentando entender el funcionamiento de todo el código, lógicamente si no lo entiendo no podré solucionar problemas, por eso estoy tan pesado en el foro, hay muchas cosas que se escapan a mi compresión aún.

Si te ayuda pongo el código del servidor y del demonio actual.
davidferrero
Perlero nuevo
Perlero nuevo
 
Mensajes: 25
Registrado: 2009-07-29 03:12 @175

Re: Demonio y servidor

Notapor explorer » 2009-08-20 07:54 @371

Si no me equivoco, pasa esto:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
my $pid1 = fork;     # Creamos un nuevo proceso desde el padre

exit(0)  if ($pid1); # Si el padre recibe el $pid1, se muere, y el hijo sigue

my $pid2 = fork;     # El hijo crea un nuevo proceso

exit(0)  if ($pid2); # Si el hijo recibe el $pid2, se muere, y su hijo sigue.
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Vamos, que al final quien continúa es el nieto... no creo que sea necesario crear tanta descendencia :)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Siguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados