1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
1
0
1
0
1
0
0
Comunicación
Características
Cada proceso seejecuta de forma
independiente, con su propio
espacio de memoria. Esto implica
que un error en un proceso rara vez
afecta a otro.
Crear y gestionar procesos requiere
más recursos y tiempo, ya que cada
proceso necesita su propio espacio
de memoria.
La comunicación entre procesos se
realiza mediante mecanismos como
pipes, sockets o colas de mensajes.
Esto es más complejo y suele ser
más lento debido a la falta de
memoria compartida.
Abrir varias aplicaciones en nuestro sistema
operativo, como un editor de texto, un
navegador y un reproductor de música. Cada
una de estas aplicaciones se ejecuta en un
proceso distinto. Si el editor de texto falla, los
otros programas seguirán funcionando.
Aislamiento Overhead Mayor
Ejemplo
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
1
0
1
0
1
0
0
Sincronización
Características
Todos los hilosde un proceso comparten la
misma memoria, lo que permite una
comunicación rápida, pero también requiere
mecanismos de sincronización (por ejemplo,
locks) para evitar conflictos.
La creación de un hilo es más rápida
y consume menos recursos que la
creación de un proceso.
Debido a la memoria compartida, es
fundamental coordinar el acceso a
recursos comunes para evitar
condiciones de carrera.
En una aplicación de edición de video,
diferentes hilos pueden encargarse de
reproducir el video, aplicar efectos y realizar la
codificación, trabajando en paralelo dentro del
mismo proceso para mejorar el rendimiento sin
necesidad de crear procesos independientes.
Memoria Compartida Overhead Menor
Ejemplo
6.
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
1
0
1
0
1
0
0
¿Qué es laconcurrencia?
Concurrencia es la capacidad de un sistema para manejar múltiples tareas al mismo
tiempo (aparente). No necesariamente significa que se estén ejecutando exactamente al
mismo segundo (eso sería paralelismo), sino que el sistema puede ir cambiando de una
tarea a otra rápidamente, dando la ilusión de simultaneidad.
Ejemplo: Imaginemos que somos un mozo en una cafetería (un solo hilo de ejecución) y
tenemos 5 mesas que nos piden cosas. No podemos atenderlas todas a la vez, pero sí
podemos:
● Anotar la orden de la mesa 1
● Mientras el café se prepara, ir a la mesa 2
● Tomar su orden
● Mientras esperamos la comida de la mesa 1, llevamos la bebida a la mesa 3
Estamos siendo concurrentes: gestionamos varias tareas sin hacerlas todas al mismo
tiempo.
7.
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
1
0
1
0
1
0
0
¿Qué es laasincronía?
Asincronía significa que una operación puede comenzar ahora y terminar más
adelante, sin detener el flujo principal del programa.
En Node.js, cuando hacemos algo que tarda (cómo leer un archivo o consultar una API), lo
hacemos de forma asíncrona. Es decir:
● Mandamos a hacer la tarea
● Mientras tanto, seguimos ejecutando otras líneas de código
● Cuando termina, Node.js nos avisa (por ejemplo, con un callback)
8.
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
1
0
1
0
1
0
0
¿Qué es elEvent Loop?
El Event Loop (bucle de eventos) es el mecanismo que permite a Node.js ejecutar código
de forma no bloqueante usando un solo hilo.
¿Cómo funciona?
1. Ejecuta el código principal línea por línea (fase "síncrona").
2. Si encuentra algo asíncrono (como lectura de archivo, consulta HTTP), lo deriva a un
componente externo (por ejemplo, el sistema operativo).
3. Cuando esa tarea termina, el event loop la mete en una cola de tareas pendientes.
4. Cuando Node.js termina el código actual, revisa esa cola y ejecuta esas funciones
(callbacks, etc.).
Imaginemos al event loop como un asistente que:
● Recibe tareas
● Las ordena
● Y las ejecuta en el momento adecuado, sin detenerse por ninguna.
9.
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
1
0
1
0
1
0
0
¿Por qué estoes útil en Node.js ?
Node.js no bloquea mientras espera operaciones lentas cómo leer archivos o consultar
bases de datos. En lugar de crear un nuevo hilo (como en otros lenguajes), usa el event
loop y asincronía para hacer más con menos.
Opciones para Paralelismo en Node.js:
➢ child_process: Permite crear procesos hijos independientes. Cada proceso hijo tiene
su propio espacio de memoria y se comunica con el proceso principal mediante IPC
(comunicación entre procesos). Es ideal para tareas que deben aislarse.
➢ worker_threads: Permite crear hilos (workers) dentro del mismo proceso para
ejecutar tareas intensivas en CPU. Estos hilos comparten memoria, lo que facilita la
comunicación, pero requieren sincronización para evitar conflictos.
10.
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
1
0
1
0
1
0
0
Opción para elProyecto FTSApp
Después de evaluar ambos enfoques, vamos a continuar con el método child_process para el
proyecto FTSApp.
Razones de la elección:
● Aislamiento y estabilidad: Cada conexión se maneja en un proceso independiente, lo que
minimiza el riesgo de que un error en una conexión afecte a las demás.
● Facilidad de depuración: Los procesos hijos tienen un entorno aislado, lo que facilita la
identificación y solución de problemas sin interferir con el proceso principal.
● Simplicidad en la implementación: Aunque los Worker Threads son más eficientes en
términos de recursos para tareas CPU-intensivas, nuestro caso de uso principal (gestión de
conexiones y mensajes simples) se beneficia del aislamiento que ofrecen los procesos hijos sin
requerir una sincronización compleja.
● Escalabilidad: En un entorno de producción, manejar conexiones en procesos separados
permite distribuir la carga entre varios núcleos o incluso máquinas, aprovechando
mecanismos de balanceo de carga.
11.
1
0
1
0
0
1
0
0
1
0
1
1
0
1
1
1
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
Explicación Nuevo Códigoen server.js
Importación de child_process:
● Se añade la línea const { fork } = require('child_process');
● Propósito: Permite crear procesos hijos que ejecuten otro archivo (en este caso, worker.js), lo que
proporciona aislamiento y manejo concurrente de conexiones.
Creación del Proceso Hijo con fork:
● Dentro del callback del servidor, al establecerse una conexión, se ejecuta:
const child = fork('./worker.js');
● Propósito: Cada vez que un cliente se conecta, se crea un proceso hijo independiente que se
encargará de procesar los datos enviados por ese cliente. Esto ayuda a aislar cada conexión y evita
que un error en una conexión afecte a las demás.
12.
1
0
1
0
0
1
0
0
1
0
1
1
0
1
1
1
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
Explicación Nuevo Códigoen server.js
Envío de Datos al Proceso Hijo:
● Se utiliza el evento socket.on('data', ...) para escuchar los datos que llegan del cliente.
● Dentro de ese callback, se envían los datos al proceso hijo con: child.send(data.toString());
● Propósito: Transferir el procesamiento de datos al proceso hijo, lo que permite que el proceso
principal se concentre en manejar las conexiones sin bloquearse en operaciones intensivas.
Recepción de Respuestas desde el Proceso Hijo:
● Se añade un manejador para el evento child.on('message', ...):
child.on('message', (message) => { socket.write(message); });
● Propósito: El proceso hijo procesa el mensaje (por ejemplo, convirtiéndolo a mayúsculas) y envía
una respuesta. Esta respuesta se reenvía al cliente, demostrando la comunicación bidireccional
entre el proceso principal y el hijo.
13.
1
0
1
0
0
1
0
0
1
0
1
1
0
1
1
1
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
Explicación Nuevo Códigoen server.js
Manejo del Cierre de Conexión:
● Al detectar que el cliente ha finalizado la conexión socket.on('end', ...), se llama a child.kill() para
terminar el proceso hijo.
● Propósito: Evitar procesos huérfanos y liberar recursos, asegurando que cada proceso hijo sólo
esté activo mientras su cliente esté conectado.
14.
1
0
1
0
0
1
0
0
1
0
1
1
0
1
1
1
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
Explicación Código enworker.js
Este archivo es invocado desde el servidor principal server.js usando child_process.fork(). Actúa como un
proceso independiente, especializado en tareas de procesamiento (en este caso por ahora, transformar
texto a mayúsculas).
process.on('message', (message) => {
● Este evento escucha los mensajes enviados desde el proceso padre (el servidor).
● message contiene el contenido enviado desde server.js usando child.send(...)
● Esto es parte del mecanismo de IPC (Inter-Process Communication) entre el padre y el hijo.
console.log(`Worker: Recibido mensaje: ${message}`);
● Simple console.log() para que veamos que recibió el worker.
● Es útil para debuguear o para mostrar cómo fluye la comunicación entre procesos.
const processed = message.toUpperCase();
● Acá se hace el "procesamiento" simulado.
● Podría ser cualquier lógica compleja: análisis, búsqueda, cifrado, etc.
● En este caso, simplemente convierte el texto a mayúsculas usando .toUpperCase().
1
0
1
0
0
1
0
0
1
0
1
1
0
1
1
1
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
Explicación Nuevo Códigoen client.js
Módulo readline:
● Propósito: Permite leer datos de la consola de forma interactiva, como si fuera un input de un
formulario, pero en terminal: const readline = require('readline');
● Creamos una interfaz de entrada:
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
● Lo Nuevo: Antes, el cliente se conectaba y recibía datos sin dar la opción de interacción manual.
Ahora, el usuario puede escribir mensajes, lo que es esencial para aplicaciones en las que se
requiere retroalimentación del usuario (por ejemplo, un chat o una terminal remota).
17.
1
0
1
0
0
1
0
0
1
0
1
1
0
1
1
1
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
Explicación Nuevo Códigoen client.js
Función preguntar():
● Propósito: Esta función utiliza rl.question() para solicitar al usuario que ingrese un mensaje. Luego,
dependiendo del input, envía ese mensaje al servidor o cierra la conexión.
● Lo Nuevo: Se implementa una función recursiva que se llama después de cada respuesta del
servidor para mantener la comunicación activa. Esto genera un ciclo donde el cliente:
○ Envía un mensaje.
○ Espera la respuesta del servidor.
○ Pide al usuario nuevamente un mensaje.
18.
1
0
1
0
0
1
0
0
1
0
1
1
0
1
1
1
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
Explicación Nuevo Códigoen client.js
Evento client.on('data', ...):
● Propósito: Detecta cuándo el servidor envía datos y, tras recibirlos, llama a la función preguntar()
para continuar la interacción.
client.on('data', (data) => {
console.log(`📨 Servidor: ${data.toString()}`);
preguntar();
● Lo Nuevo: En la versión base, el cliente solo recibía un mensaje y cerraba la conexión. Ahora, se
vuelve a invocar la función que solicita input al usuario, permitiendo conversaciones continuas.
19.
1
0
1
0
0
1
0
0
1
0
1
1
0
1
1
1
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
Explicación Nuevo Códigoen client.js
Manejo de Eventos 'close' y 'error':
● Propósito: Garantiza que, en caso de que el servidor cierre la conexión o se produzca un error, la
interfaz de entrada se cierre adecuadamente y se informe al usuario.
client.on('close', () => {
console.log('🔒 Conexión cerrada por el servidor.');
rl.close();
});
client.on('error', (err) => {
console.error('❌ Error en el cliente:', err.message);
rl.close();
});
● Lo Nuevo: El manejo de estos eventos es importante para proteger la aplicación y asegurarse de
que la sesión interactiva se cierre de forma ordenada si ocurre un problema.
20.
1
0
1
0
0
1
0
0
1
0
1
1
0
1
1
1
1
0
0
1
0
1
0
1
0
0
1
0
1
0
1
0
Explicación Nuevo Códigoen client.js
Persistencia de la Conexión:
● Propósito: En lugar de cerrar la conexión inmediatamente después de recibir un mensaje (como en
la versión base), se permite que el usuario envíe múltiples mensajes
● Lo Nuevo: La conexión solo se cierra cuando el usuario escribe "salir", lo que posibilita una
interacción continua.