ANUNCIOS
Imagen de Articulo

CREACION DE UN PEQUEÑO SERVIDOR WEB COMO EJEMPLO DE PROCESOS DEMONIOS Y SOCKETS EN LINUX

A continuación se muestra la creación un proceso demonio en linux, el cual funciona con sockets. la aplicación se desarrolló en C++ y hace uso de las llamadas al sistema. El demonio espera que se realize una petición HTTP, atravez del puerto 80 y retorna un resultado a esta petición, que no será mas que un archivo guardado en la carpeta que se registra en config.cfg. Cuando se recibe la petición desde el cliente, se crea un hilo que guarda en el archivo daemon.log el registro de la petición.

La aplicación hace uso de funciones tanto para crear un proceso hijo como hilos.

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <time.h>


#include <string>


pthread_mutex_t mutexBuffer; //Usado para la exclusion mutua

void * crear_registro(void * );

using namespace std;


void error(const char *msg){
    perror(msg);
    crear_registro((void *) msg );
    exit(1);
}

typedef struct {
  int lSize;
  char * cadena;
  bool error;
} Cadena;


Cadena read_file_src(const char * directorio){

  Cadena web;
  FILE * pFile;

  char * buffer;
  size_t result;

  pFile = fopen ( directorio , "rb" );
  if (pFile==NULL) {
        web.cadena = (char *)malloc(sizeof(char)*50);
        bzero(web.cadena,50);
        sprintf(web.cadena,"HTTP/1.0 404 Not Found");
        web.lSize = 50;
    web.error = true;
        return web;
  }

  // Obtener el tamaño del archivo
  fseek (pFile , 0 , SEEK_END);
  web.lSize = ftell (pFile);
  rewind (pFile);

  // Reserva memoria
  buffer = (char*) malloc (sizeof(char)*web.lSize);
  bzero(buffer,web.lSize);
 
 if (buffer == NULL) {
      web.cadena = (char *)malloc(sizeof(char)*50);
      bzero(web.cadena,50);
      sprintf(web.cadena,"HTTP/1.0 500 Server error");
      web.lSize = 50;
      web.error = true;
      return web;
  }


  //Copia el archivo al buffer
  result = fread (buffer,1,web.lSize,pFile);
  if (result != web.lSize) {

      web.cadena = (char *)malloc(sizeof(char)*50);
      bzero(web.cadena,50);
      sprintf(web.cadena,"HTTP/1.0 404 Not found");
      web.error = true;
      web.lSize = 50;
     return web;
  }


   fclose (pFile);
   web.cadena = buffer;
   web.error = false;
 
  return web;
}


void * crear_registro(void * buffer){
  
  
   char * insertar = (char *) buffer;
   FILE * pFile;
  
   /* Obtenemos el tiempo del sistema */
   time_t tiempo = time(0) - 5*60*60 ;
   struct tm *tlocal = gmtime(&tiempo);
   char fecha[200];
 
   /* Obtenemos una cadena con la fecha que tiene el
   formato establecido. */
   strftime(fecha,200,"%d/%m/%y %I:%M:%S %P",tlocal);
  
   pthread_mutex_lock (&mutexBuffer);
   pFile = fopen ("daemon.log","a");

   const char * aux = "\n\n------------------------------------\nFecha: " ;
   fwrite (aux,sizeof(char), strlen(aux) , pFile);

   fwrite ( fecha,sizeof(char), strlen(fecha),pFile);

   aux = "\n-->Peticion:\n";
   fwrite (aux,sizeof(char), strlen(aux) -1 , pFile);

   fwrite (insertar,sizeof(char), strlen(insertar),pFile );


  
   fclose (pFile);
   pthread_mutex_unlock (&mutexBuffer);
  return 0;
}

int main(int argc, char *argv[]) {

 /* Iniciamos la función bloqueante del hilo */
 
     pthread_mutex_init (&mutexBuffer, NULL);
    pthread_t idHilo;



//----------------------------------------------------------

    //obtenemos el tiempo del sistema
       time_t tiempo = time(0)- 5*60*60;
       struct tm *tlocal = gmtime(&tiempo);
 
       char fecha[200];
       //obtenemos una cadena con la fecha que tiene el
       //formato establecido.
       strftime(fecha,200,"%d/%m/%y %I:%M:%S %P",tlocal);
    printf("\n\nFecha:%s\n",fecha);

//----------------------------------------------------------

      /* 
       *  Leemos el archivo raiz desde el archivo config.cfg
       */

       Cadena raiz = read_file_src("./config.cfg");
       raiz.cadena[raiz.lSize - 2] = '\0';
       printf("\n\n-------Iniciando-------\n\nDirectorio raiz: %s\n", raiz.cadena);



       printf("Iniciando Proceso demonio...\n");
      
       pid_t pid, sid; //en pid se guardará el pid del hijo en el padre, en sid se guardará el pid del hijo en el hijo
       
        /* Bifurca el proceso padre */

        pid = fork();
        if (pid < 0) {
            printf("El Pid no es el indicado...\n");
                exit(EXIT_FAILURE);
        }
 
       /* Si el pid del hijo esta bien cerramos el padre. */
        if (pid > 0) {
                printf("Numero de proceso hijo %i \n", pid);
                printf("Matando al proceso padre...\n");
                exit(EXIT_SUCCESS);
        }
       crear_registro( (void *) "Iniciado proceso demonio... \n");


        /* Establece los permisos por defecto para los nuevos archivos y directorios creados por el proceso actual. */
        umask(0);
               
                       
        /* El proceso hijo toma el control de la sesión*/
        sid = setsid();
        if (sid < 0)
                error("Error en setsid");
       
        /* Cambiamos el directorio raiz al leido en la primer instancia */
      
        if ((chroot(raiz.cadena)) < 0)
                error("No se ha podido cambiar el directorio raiz");
       
       free(raiz.cadena);

       
        /* Cerramos los descriptores estandar de archivo */

        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
       

      
    
     char buffer[4000]; /* Buffer para guardar la petición realizada por el cliente */
   
     /* sockaddr_in es una estructura que permite administrar información del socket como dirección y numero de puerto*/
     struct sockaddr_in serv_addr, cli_addr;
     int sockfd, newsockfd, portno;
     socklen_t clilen = sizeof(cli_addr);
     int n;
    
     sockfd = socket(AF_INET, SOCK_STREAM, 0); /* Creamos un punto final de comunicacion */
     if (sockfd < 0)
        error("ERROR abriendo el puerto");
    
     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = 80;
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
    
     /* Enlazamos el soket a un puerto y a una direccion */
     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0)
              error("ERROR en enlazado del socket al puerto y dirección");
   
  
     /* escuchar el puerto */
     listen(sockfd,5);

    while (1) {

     newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); /* Aceptamos la conexión del cliente al socket */
 
    if (newsockfd < 0) error("ERROR cliente no aceptado");
    
     bzero(buffer,4000);

     n = read(newsockfd,buffer  , 4000); /* Leemos la información enviada desde el cliente */
     if (n < 0) error("ERROR leyendo desde el socket");

    
     pthread_create (&idHilo, NULL, crear_registro, (void *)buffer);

     /* Obtenemos la dirección del directorio que ha solicitado el cliente */
  
     string directorio =   buffer + 4 ;
     int posicion = directorio.find(" ");
     directorio = directorio.substr(0, posicion);

     if(directorio[posicion - 1]  == '/' )
      directorio += "index.html";
    
     /* Leemos el archivo que fue requerido por el cliente */

     Cadena cadena = read_file_src(directorio.c_str());


     /* Enviamos la respuesta al cliente */
      n = write(newsockfd,cadena.cadena,cadena.lSize);
     if (n < 0) error("ERROR escribiendo al socket");
   
       close(newsockfd); /* Cerramos la conexión con el cliente */
       free(cadena.cadena);
        
     }
 
   close(sockfd); /* Cerramos el socket */
 
   exit(EXIT_SUCCESS);
}


Descargar archivo . Para compilar g++ daemon.cpp -o httpd -lpthread.

Etiquetas:   PROCESOS

Articulos Relacionados
Publicidad
Comentarios
comments powered by Disqus