Ejemplos de Websocket de Node.js con Socket.io

E

¿Qué son los Websockets?

En los últimos años, un nuevo tipo de comunicación comenzó a surgir en la web y en las aplicaciones móviles, llamado websockets. Este protocolo ha sido esperado durante mucho tiempo y finalmente fue estandarizado por la IETF en 2011, allanando el camino para un uso generalizado.

Este nuevo protocolo abre una línea de comunicación con el cliente mucho más rápida y eficiente. Al igual que HTTP, los websockets se ejecutan sobre una conexión TCP, pero son mucho más rápidos porque no tenemos que abrir una nueva conexión cada vez que queremos enviar un mensaje, ya que la conexión se mantiene activa mientras el servidor o el cliente quiere.

Aún mejor, dado que la conexión nunca termina, finalmente tenemos comunicación full-duplex disponible, lo que significa que podemos enviar datos al cliente en lugar de tener que esperar a que soliciten datos del servidor. Esto permite que los datos se comuniquen de un lado a otro, lo que es ideal para cosas como aplicaciones de chat en tiempo real o incluso juegos.

¿Cómo funcionan los Websockets?

En esencia, un websocket es solo una conexión TCP que permite la comunicación full-duplex, lo que significa que cualquier lado de la conexión puede enviar datos al otro, incluso al mismo tiempo.

Para establecer esta conexión, el protocolo en realidad inicia el protocolo de enlace como una solicitud HTTP normal, pero luego se ‘actualiza’ usando el solicitud de actualización Encabezado HTTP, como este:

GET /ws/chat HTTP/1.1
Host: chat.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: q1PZLMeDL4EwLkw4GGhADm==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 15
Origin: http://example.com

Luego, el servidor envía una respuesta HTTP 101 “Protocolos de conmutación”, reconociendo que la conexión se actualizará. Una vez realizada esta conexión, cambia a un protocolo binario bidireccional, momento en el que se pueden enviar los datos de la aplicación.

Todo lo que tiene que hacer el protocolo para mantener la conexión abierta es enviar algunos paquetes de ping / pong, lo que le dice al otro lado que todavía están allí. Para cerrar la conexión, se envía un paquete simple de “cerrar conexión”.

Algunos ejemplos de Websocket

De las muchas bibliotecas websocket diferentes para Node.js disponibles para nosotros, elegí usar socket.io a lo largo de este artículo porque parece ser el más popular y, en mi opinión, el más fácil de usar. Si bien cada biblioteca tiene su propia API única, también tienen muchas similitudes, ya que todas están construidas sobre el mismo protocolo, por lo que es de esperar que pueda traducir el código a continuación a cualquier biblioteca que desee usar.

Para el servidor HTTP, usaré Rápido, que es el servidor de node más popular que existe. Tenga en cuenta que también puede usar el simple http módulo si no necesita todas las funciones de Express. Aunque, dado que la mayoría de las aplicaciones usarán Express, eso es lo que usaremos también.

Nota: A lo largo de estos ejemplos, he eliminado gran parte del código estándar, por lo que parte de este código no funcionará de inmediato. En la mayoría de los casos, puede consultar el primer ejemplo para obtener el código estándar.

Establecer la conexión

Para que se establezca una conexión entre el cliente y el servidor, el servidor debe hacer dos cosas:

  • Conéctese al servidor HTTP para manejar las conexiones websocket
  • Sirva el socket.io.js biblioteca cliente como recurso estático

En el siguiente código, puede ver que el elemento (1) se realiza en la tercera línea. El elemento (2) está hecho para usted (por defecto) por el socket.io biblioteca y se sirve en el camino /socket.io/socket.io.js. De forma predeterminada, todas las conexiones y recursos de websocket se sirven dentro del /socket.io camino.

Servidor

var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);

app.get("https://Pharos.sh.com/", function(req, res) {
    res.sendFile(__dirname + '/index.html');
});

server.listen(8080);

El cliente también debe hacer dos cosas:

  • Cargue la biblioteca desde el servidor
  • Llamada .connect() a la dirección del servidor y la ruta de websocket

Cliente

<script src="/socket.io/socket.io.js"></script>
<script>
    var socket = io.connect("https://Pharos.sh.com/");
</script>

Si navega con su navegador a http://localhost:8080 e inspeccionar las solicitudes HTTP detrás de escena utilizando las herramientas de desarrollo de su navegador, debería poder ver el protocolo de enlace que se está ejecutando, incluidas las solicitudes GET y la respuesta resultante de los protocolos de conmutación HTTP 101.

Envío de datos del servidor al cliente

Bien, ahora pasemos a algunas de las partes más interesantes. En este ejemplo, le mostraremos la forma más común de enviar datos desde el servidor al cliente. En este caso, enviaremos un mensaje a un canal, al que el cliente puede suscribirse y recibir. Entonces, por ejemplo, una aplicación cliente podría estar escuchando en el canal de ‘anuncios’, que contendría notificaciones sobre eventos en todo el sistema, como cuando un usuario se une a una sala de chat.

En el servidor, esto se hace esperando a que se establezca la nueva conexión, luego llamando al socket.emit() método para enviar un mensaje a todos los clientes conectados.

Servidor

io.on('connection', function(socket) {
    socket.emit('announcements', { message: 'A new user has joined!' });
});

Cliente

<script src="/socket.io/socket.io.js"></script>
<script>
    var socket = io.connect("https://Pharos.sh.com/");
    socket.on('announcements', function(data) {
        console.log('Got announcement:', data.message);
    });
</script>

Envío de datos de cliente a servidor

Pero, ¿qué haríamos cuando queramos enviar datos al revés, de cliente a servidor? Es muy similar al último ejemplo, utilizando tanto el socket.emit() y socket.on() métodos.

Servidor

io.on('connection', function(socket) {
    socket.on('event', function(data) {
        console.log('A client sent us this dumb message:', data.message);
    });
});

Cliente

<script src="/socket.io/socket.io.js"></script>
<script>
    var socket = io.connect("https://Pharos.sh.com/");
    socket.emit('event', { message: 'Hey, I have an important message!' });
</script>

Contando usuarios conectados

Este es un buen ejemplo para aprender, ya que muestra algunas características más de socket.io (como el disconnect event), es fácil de implementar y es aplicable a muchas aplicaciones web. Usaremos el connection y disconnect eventos para contar el número de usuarios activos en nuestro sitio, y actualizaremos a todos los usuarios con el recuento actual.

Servidor

var numClients = 0;

io.on('connection', function(socket) {
    numClients++;
    io.emit('stats', { numClients: numClients });

    console.log('Connected clients:', numClients);

    socket.on('disconnect', function() {
        numClients--;
        io.emit('stats', { numClients: numClients });

        console.log('Connected clients:', numClients);
    });
});

Cliente

<script src="/socket.io/socket.io.js"></script>
<script>
    var socket = io.connect("https://Pharos.sh.com/");
    socket.on('stats', function(data) {
        console.log('Connected clients:', data.numClients);
    });
</script>

Una forma mucho más simple de rastrear el número de usuarios en el servidor sería simplemente usar esto:

var numClients = io.sockets.clients().length;

Pero aparentemente hay algunos asuntos en torno a esto, por lo que es posible que tenga que realizar un seguimiento del recuento de clientes usted mismo.

Salas y espacios de nombres

Lo más probable es que a medida que su aplicación crezca en complejidad, necesitará más personalización con sus websockets, como enviar mensajes a un usuario específico o conjunto de usuarios. O tal vez desee necesitar una estricta separación de la lógica entre las diferentes partes de su aplicación. Aquí es donde entran en juego las habitaciones y los espacios de nombres.

Nota: Estas funciones no forman parte del protocolo websocket, pero se agregan socket.io.

Por defecto, socket.io usa el espacio de nombres raíz (/) para enviar y recibir datos. Mediante programación, puede acceder a este espacio de nombres a través de io.sockets, aunque muchos de sus métodos tienen atajos en io. Entonces estas dos llamadas son equivalentes:

io.sockets.emit('stats', { data: 'some data' });
io.emit('stats', { data: 'some data' });

Para crear su propio espacio de nombres, todo lo que tiene que hacer es lo siguiente:

var iosa = io.of('/Pharos.sh');
iosa.on('connection', function(socket){
    console.log('Connected to Stack Abuse namespace'):
});
iosa.emit('stats', { data: 'some data' });

Además, el cliente debe conectarse a su espacio de nombres explícitamente:

<script src="/socket.io/socket.io.js"></script>
<script>
    var socket = io('/Pharos.sh');
</script>

Ahora cualquier dato enviado dentro de este espacio de nombres estará separado del predeterminado / espacio de nombres, independientemente del canal que se utilice.

Yendo aún más lejos, dentro de cada espacio de nombres puede unirse y salir de ‘salas’. Estas salas proporcionan otra capa de separación en la parte superior de los espacios de nombres y, dado que un cliente solo se puede agregar a una sala en el lado del servidor, también brindan cierta seguridad adicional. Entonces, si desea asegurarse de que los usuarios no estén fisgoneando en ciertos datos, puede usar una sala para ocultarlos.

Para ser agregado a una habitación, debe .join() eso:

io.on('connection', function(socket){
    socket.join('private-message-room');
});

Luego, desde allí, puede enviar mensajes a todos los que pertenecen a la sala determinada:

io.to('private-message-room').emit('some event');

Y finalmente, llama .leave() para dejar de recibir mensajes de eventos de una sala:

socket.leave('private-message-room');

Conclusión

Esta es solo una biblioteca que implementa el protocolo websockets, y hay muchas más, todas con sus propias características y fortalezas únicas. Aconsejaría probar algunos de los otros (como node-websockets) para que tengas una idea de lo que hay ahí fuera.

En solo unas pocas líneas, puede crear algunas aplicaciones bastante poderosas, ¡así que tengo curiosidad por ver qué se le ocurre!

¿Tiene algunas ideas interesantes o ya ha creado algunas aplicaciones con websockets? ¡Háznoslo saber en los comentarios!

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad