Funcionalidades y características del servidor
Este servidor es modular y cuenta con las siguientes características clave:
-
Manejo de múltiples solicitudes HTTP:
-
Soporta métodos
GET
,POST
,PUT
,PATCH
, yDELETE
, lo que permite procesar diferentes tipos de solicitudes para gestionar recursos. - Permite manejar solicitudes dinámicas con encabezados personalizados.
-
Soporta métodos
-
Seguridad mediante HTTPS:
- Utiliza OpenSSL para establecer conexiones seguras con SSL/TLS, cumpliendo con estándares internacionales como RFC 5246.
- Protege la transferencia de datos entre el cliente y el servidor.
-
Registro de eventos:
-
Guarda solicitudes y respuestas en un archivo de registro
(
server.log
), lo que facilita la trazabilidad y el monitoreo.
-
Guarda solicitudes y respuestas en un archivo de registro
(
-
Autenticación básica:
-
Verifica solicitudes mediante encabezados HTTP de autorización
(
Authorization
). - Permite un acceso controlado a través de credenciales (usuario y contraseña).
-
Verifica solicitudes mediante encabezados HTTP de autorización
(
-
Soporte para múltiples formatos:
-
Responde en formatos JSON, XML y HTML,
adaptándose al encabezado
Accept
de las solicitudes HTTP. - Facilita la interoperabilidad con diferentes sistemas y aplicaciones.
-
Responde en formatos JSON, XML y HTML,
adaptándose al encabezado
-
Modularidad:
-
Está estructurado en módulos independientes
(
request_handler
,ssl_handler
,auth
, etc.), lo que facilita su mantenimiento y ampliación.
-
Está estructurado en módulos independientes
(
¿Se puede usar como backend y frontend?
Backend:
Sí, este servidor puede funcionar como un backend para gestionar contenido. Algunas de sus capacidades como backend incluyen:
-
Almacenar información desde el frontend:
-
Con los métodos
POST
,PUT
, yPATCH
, el servidor puede recibir datos del frontend y guardarlos en archivos, lo cual simula un sistema de almacenamiento. - Ejemplo: Al enviar un formulario desde el frontend, el servidor puede escribir los datos en un archivo.
-
Con los métodos
-
Recuperar datos para el frontend:
-
Usando el método
GET
, el servidor puede devolver información previamente almacenada, permitiendo que el frontend muestre contenido dinámico.
-
Usando el método
Frontend:
Aunque el servidor puede enviar respuestas en formato HTML, no está diseñado para manejar tareas específicas de un frontend avanzado, como interfaces interactivas o dinámicas. Es posible usarlo para servir contenido estático, pero necesitarías herramientas complementarias como frameworks de JavaScript (React, Angular, etc.) para crear un frontend robusto.
¿Es escalable?
Este servidor tiene cierta capacidad de escalabilidad, pero hay consideraciones importantes:
-
Escalabilidad horizontal:
- Podrías ejecutar múltiples instancias del servidor en diferentes máquinas y usar un balanceador de carga para distribuir solicitudes.
-
Limitaciones:
- Manejo de datos: Actualmente, los datos se almacenan en archivos locales, lo cual no es óptimo para grandes volúmenes de información. Para escalar, deberías integrar bases de datos como MySQL, PostgreSQL, MongoDB, etc.
- Manejo de clientes simultáneos: Aunque utiliza threads (hilos) para manejar clientes concurrentemente, la cantidad de clientes estará limitada por los recursos del sistema (CPU, memoria).
-
Recomendaciones para escalabilidad:
- Optimización de almacenamiento: Migrar de archivos locales a una base de datos.
- Ampliación de seguridad: Implementar autenticación más avanzada (por ejemplo, OAuth2) y cifrado de datos sensible.
- Integración con tecnologías modernas: Usar contenedores como Docker y herramientas de orquestación como Kubernetes para escalar el servidor de forma eficiente.
¿Es viable para proyectos reales?
Sí, con ciertas mejoras, este servidor puede ser usado como parte de un sistema real. Aquí tienes los puntos clave:
- Proyectos pequeños: Ideal para aplicaciones educativas, prototipos o sistemas embebidos.
- Proyectos grandes: Requiere escalabilidad, integración con bases de datos y autenticación más avanzada para funcionar como un backend completo en producción.
modular_server/
├── main.c
├── server.c
├── server.h
├── ssl_handler.c
├── ssl_handler.h
├── auth.c
├── auth.h
├── event_logger.c
├── event_logger.h
├── request_handler.c
├── request_handler.h
├── Makefile
├── server.crt # Certificado SSL
├── server.key # Llave privada SSL
request_handler.c
Este archivo implementa la lógica de manejo de solicitudes HTTP que serán procesadas por el servidor.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "request_handler.h"
#include "auth.h"
#include "event_logger.h"
// Tamaño máximo del buffer para solicitudes/respuestas
#define BUFFER_SIZE 4096
void handle_request(int client_socket, SSL_CTX *ctx) {
char buffer[BUFFER_SIZE] = {0};
SSL *ssl = SSL_new(ctx);
SSL_set_fd(ssl, client_socket);
if (SSL_accept(ssl) <= 0) {
log_event("Error en el handshake SSL.");
SSL_free(ssl);
return;
}
SSL_read(ssl, buffer, BUFFER_SIZE);
printf("Solicitud recibida:\n%s\n", buffer);
// Registrar la solicitud
log_event(buffer);
// Analizar el encabezado de autorización
char *auth_header = strstr(buffer, "Authorization: ");
if (auth_header) {
auth_header += strlen("Authorization: ");
strtok(auth_header, "\r\n"); // Eliminar saltos de línea
if (!authenticate_request(auth_header)) {
const char *response = "HTTP/1.1 401 Unauthorized\r\nContent-Type: text/plain\r\n\r\nNo autorizado.";
SSL_write(ssl, response, strlen(response));
SSL_free(ssl);
return;
}
} else {
const char *response = "HTTP/1.1 401 Unauthorized\r\nContent-Type: text/plain\r\n\r\nNo autorizado.";
SSL_write(ssl, response, strlen(response));
SSL_free(ssl);
return;
}
// Analizar la solicitud para manejar diferentes métodos HTTP
if (strncmp(buffer, "GET", 3) == 0) {
const char *response =
"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSolicitud GET manejada correctamente.\n";
SSL_write(ssl, response, strlen(response));
} else if (strncmp(buffer, "POST", 4) == 0) {
const char *response =
"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSolicitud POST manejada correctamente.\n";
SSL_write(ssl, response, strlen(response));
} else if (strncmp(buffer, "PUT", 3) == 0) {
const char *response =
"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSolicitud PUT manejada correctamente.\n";
SSL_write(ssl, response, strlen(response));
} else if (strncmp(buffer, "PATCH", 5) == 0) {
const char *response =
"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSolicitud PATCH manejada correctamente.\n";
SSL_write(ssl, response, strlen(response));
} else if (strncmp(buffer, "DELETE", 6) == 0) {
const char *response =
"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSolicitud DELETE manejada correctamente.\n";
SSL_write(ssl, response, strlen(response));
} else {
const char *response =
"HTTP/1.1 405 Method Not Allowed\r\nContent-Type: text/plain\r\n\r\nMétodo no permitido.";
SSL_write(ssl, response, strlen(response));
}
// Liberar recursos de SSL
SSL_free(ssl);
}
request_handler.h
Este archivo declara la función de manejo de solicitudes para que pueda usarse en otros módulos.
#ifndef REQUEST_HANDLER_H
#define REQUEST_HANDLER_H
#include <openssl/ssl.h>
// Declaración de la función de manejo de solicitudes
void handle_request(int client_socket, SSL_CTX *ctx);
#endif
Makefile
CC = gcc
CFLAGS = -Wall -Wextra -I.
LIBS = -lssl -lcrypto
all: server
server: main.o server.o ssl_handler.o auth.o event_logger.o request_handler.o
$(CC) -o server main.o server.o ssl_handler.o auth.o event_logger.o request_handler.o $(LIBS)
main.o: main.c server.h
$(CC) $(CFLAGS) -c main.c
server.o: server.c server.h ssl_handler.h auth.h event_logger.h request_handler.h
$(CC) $(CFLAGS) -c server.c
ssl_handler.o: ssl_handler.c ssl_handler.h
$(CC) $(CFLAGS) -c ssl_handler.c
auth.o: auth.c auth.h
$(CC) $(CFLAGS) -c auth.c
event_logger.o: event_logger.c event_logger.h
$(CC) $(CFLAGS) -c event_logger.c
request_handler.o: request_handler.c request_handler.h
$(CC) $(CFLAGS) -c request_handler.c
clean:
rm -f *.o server
Generar certificados SSL
Si aún no tienes server.crt
y server.key
, crea un
certificado SSL autofirmado:
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes
Compilar el servidor
Desde la carpeta modular_server
, ejecuta:
make
Esto generará el ejecutable server
.
make
Ejecutar el servidor:
./server
Probar el servidor
Haz solicitudes al servidor usando herramientas como curl
:
GET:
curl -X GET https://localhost:8080 -k
POST:
curl -X POST https://localhost:8080 -k
Con autenticación:
curl -u usuario:contraseña https://localhost:8080 -k
Resumen
-
request_handler.c
procesa solicitudes HTTP según el método (GET
,POST
, etc.). -
request_handler.h
declara las funciones necesarias para que el servidor utilice este módulo. -
Makefile
actualizado asegura que todos los módulos se compilen correctamente.
El servidor está completamente modularizado y funcional.