header_lecciones_v5

Implementación de una aplicación de mensajería utilizando socket.io

por Cristian Camilo Pérez, el 24 de febrero de 2020

Implementación de una aplicación de mensajería utilizando socket.io

¿Qué es un socket?

Podría definirse como un tipo de 'puerto' en el cual se establece una comunicación abierta donde los datos fluyen bidireccionalmente entre cliente y servidor.

¿Por qué usar sockets?

Los sockets no necesitan que se envíe una petición para poder responder. Ellos permiten un flujo de datos bidireccional por lo tanto solo es necesario escuchar el servidor y éste enviará un mensaje cuando esté disponible.

¿Para qué tipo de aplicaciones es apropiado utilizarlos?

  • Aplicaciones de mensajería (Chats)
  • Estadísticas en tiempo real.
  • Colaboración en documentos.
  • Streaming binario.

Algunas diferencias entre Sockets y REST

  1. Los Sockets requieren el uso de la dirección IP y el puerto, mientras que la aplicación RESTful necesita diseñar operaciones basadas en los verbos HTTP.
  2. Los Sockets son bidireccionales, es decir, es posible realizar operaciones en ambos sentidos de cliente al servidor y viceversa, mientras que REST sigue un enfoque unidireccional.
  3. Los sockets son un protocolo stateful mientras que REST está basado en un protocolo stateless (Todo el estado es manejado en el lado del cliente).
  4. El enfoque de WebSocket es ideal para aplicaciones escalables en tiempo real, mientras que REST es más adecuado para el escenario con muchas solicitudes.

Para implementar la aplicación vamos a utilizar una librería Javascript basada en eventos llamada socket.io.

¿Por qué utilizar socket.io?

  • Las conexiones se establecen incluso en presencia de: proxies, balanceadores de carga, firewalls y software antivirus.
  • Un cliente desconectado intentará volver a conectarse por siempre, hasta que el servidor vuelva a estar disponible.
  • Se implementa un mecanismo de latido en el nivel Engine.IO, lo que permite que tanto el servidor como el cliente sepan cuándo el otro ya no responde.

Ahora sí, empecemos a construir nuestra aplicación de mensajería en node.js con el objetivo de poner en práctica lo definido anteriormente.

Diagrama de funcionamiento

Diagrama de funcionamiento Socket

 

Configuración del entorno de desarrollo

Lo primero que debemos realizar es la creación de nuestro proyecto node, para esto corremos el siguiente comando.

Configuración del entorno de desarrollo Socket 2

Se instalan las dependencias.

Configuración del entorno de desarrollo Socket 3

Implementación del servidor

Creamos un nuevo archivo llamado server.js

Implementación del servidor socket

Ahora copiamos el siguiente código, para configurar nuestro servidor:

const http = require('http'); const express = require('express'); const socketIo = require('socket.io'); const app = express(); // Set up server const server = http.createServer(app); const io = socketIo(server); io.on('connection', socket => { console.log('User connected!'); socket.on('join', user => { socket.user = { ...user, id: socket.client.id }; const activeUsers = socket.client.conn.server.clientsCount; socket.emit('login', { activeUsers, user: socket.user }); socket.broadcast.emit('new user', { activeUsers, user: socket.user }); }); socket.on('message', msg => { socket.broadcast.emit('message', msg); }); socket.on('disconnect', () => { console.log('User disconnected!'); socket.broadcast.emit('left', { activeUsers: socket.client.conn.server.clientsCount, user: socket.user }); }); }); const port = process.env.PORT || 9000; server.listen(port, () => console.log(`App running on port ${port}`));

 

Se definieron tres eventos:

  • join: Notifica cuando un usuario ha entrado a la aplicación y lo emite a todos los clientes.
  • message: Notifica cuando un mensaje ha llegado y lo emite a todos los clientes.
  • disconnect: Evento reservado por socket.io el cual notifica cuando un cliente ha salido

Socket

La estructura de nuestro proyecto queda de la siguiente manera:

Estructura proyecto socket

Ahora ejecutamos el servidor. Deberíamos ver el siguiente mensaje de salida:

Servidor socket

Nota: Eventos importantes de socket.io.

// En escucha de evento socket.on('escuchando', ...data) // Enviar al emisor socket.emit('enviar a emisor', ...data) // Enviar a todos los clientes excepto al emisor socket.broadcast.emit('enviar a todos excepto emisor', ...data) // Enviar a todos los clientes conectados io.emit('enviar a todos', ...data)

Implementación del cliente

Socket.io nos brinda una librería que funciona tanto en cliente como servidor precisamente para conseguir la conexión bidireccional. En este caso se desarrolló un cliente utilizando React. Como el objetivo de la lección no es aprender react, entonces vamos a ejecutar los siguientes comandos para clonar el repositorio que contiene el código:

git clone git@github.com:crperz/chat-app.git cd chat-app/front

Ahora ejecutemos el código en localhost:

npm install npm start

Deberíamos de ver el siguiente mensaje de salida:

Código en localhost socket

Esto significa que la aplicación ahora se está ejecutando. Para probar su funcionamiento se pueden abrir dos pestañas del navegador y chatear consigo mismo en localhost, pero esto no es muy interesante, porque la idea es poder chatear con más personas fuera de la máquina local.

Para resolver este problema, vamos a empaquetar la aplicación en un contenedor de docker y luego se propone su ejecución en AWS.

Dockerización

El primer paso para empaquetar la aplicación en un contenedor Docker es agregar un Dockerfile al proyecto. Este archivo es una serie de instrucciones que le indican a Docker cómo ensamblar una imagen (instalación de dependencias, pasos de compilación y ejecución de la aplicación). Veamos el Dockerfile.

# Descarga de la imagen base FROM node:12.14.1-alpine # Crear el directorio WORKDIR /usr/src/app # [<ubicación de="" los="" archivos="" a="" copiar="">, ] COPY package*.json ./ # Instalación de dependencias RUN npm install # Copiar los demás archivos de la node app (docker cachea lo que ya tiene por lo tanto mejora el rendimiento al hacer las builds) COPY . . # El puerto por el cual va a exponer el contenedor, es el mismo puerto por donde está escuchando node EXPOSE 9000 # Run app CMD ["node", "server.js"] </ubicación>

Para construir la imagen y luego ejecutarla se usan los siguientes comandos:

docker build -t chat . docker run -d --name chat-app -p 9000:9000 chat

Arquitectura de despliegue AWS Fargate

El resultado es un proceso Node.js en un contenedor que ejecuta un servidor socket.io. Este contenedor se ejecuta en AWS Fargate y se expone a través de una ELB.

chat

 

Código fuente

https://github.com/crperz/chat-app

 

Guía para crear una aplicación serverless en 4 pasos

Temas:Desarrollo de Software

Lecciones Pragma

Lecciones en Academia Pragma

Aquí encontrarás tutoriales técnicos para que apliques en temas de desarrollo de software, cloud, calidad en software y aplicaciones móviles. 

También puedes visitar nuestro Blog con contenido actual sobre Transformación Digital, Marketing, Conocimiento de Usuario y más. 

Blog

Suscríbete a la academia

Descarga la Guía para trabajar con ambientes IBM Websphere Portal