Primeros pasos con WebSockets: una sala de chat simple

Este artículo se publicó por primera vez en mi cuenta pública: Front-end watermelon brother

Hola a todos, soy el hermano sandía front-end Hoy usamos WebSocket para implementar una sala de chat simple.

WebSocket es un protocolo de capa de aplicación, algo similar a HTTP. Pero a diferencia de HTTP, admite verdadero dúplex completo, es decir, no solo el cliente puede enviar mensajes de forma activa al servidor, sino que el servidor también puede enviar mensajes de forma activa al cliente.

Especialmente lo último, dejemos de implementar notificaciones del lado del servidor basadas en la forma ineficiente de sondeo largo o breve de HTTP. En comparación con HTTP, la inserción del servidor de WebSocket es más ligera y puede reducir la presión sobre el servidor.

Servidor

nodejs no proporciona un módulo WebSocket nativo. Si desea implementarlo, debe implementarlo en función del módulo de red y de acuerdo con el estándar WebSocket.

Debido a que la implementación es muy complicada, opté por usar la tercera biblioteca ws directamente.

yarn add ws
复制代码

Al igual que los módulos http nativos de nodejs, la biblioteca ws es compatible con el servidor o cliente WebSocket y proporciona API de bajo nivel.

Primero implementemos el código del servidor:

import { WebSocketServer } from "ws";

// 创建一个 ws 服务
const wsSever = new WebSocketServer({
  port6060,
});

// 每当一个客户端进行了 ws 连接,就会创建一个 ws 对象
wsSever.on("connection"(ws) => {
  // 新客户端连接时,广播
  wsSever.clients.forEach((client) => {
    client.send(`有人进入聊天室,当前聊天室人数:${wsSever.clients.size}`);
  });

  // 广播任何客户端发送的消息
  ws.on("message"(data) => {
    const msg = data.toString();
    wsSever.clients.forEach((client) => {
      client.send(msg);
    });
  });

  // 当有客户端退出时,广播
  ws.on("close"() => {
    wsSever.clients.forEach((client) => {
      client.send(`有人退出了聊天室,当前聊天室人数:${wsSever.clients.size}`);
    });
  });
});
复制代码

Cada vez que un cliente realiza una conexión websocket, activará el connectionevento y luego obtendrá un objeto ws.

Este objeto ws representa la conexión entre un determinado cliente y el servidor , a través del cual podemos recibir mensajes del cliente correspondiente y permitir que el servidor envíe mensajes activamente al cliente especificado.

El objeto ws recién creado se guardará en la colección wsServer.clients cuando se establezca la conexión y se eliminará una vez que se cierre la conexión. Entonces podemos usar este wsServer.clients para transmitir e implementar la función de la sala de chat.

cliente

El cliente usa el objeto WebSocket nativo para establecer una conexión WebSocket con el servidor.

const ws = new WebSocket('ws://localhost:6060');

ws.addEventListener('message', (event) => {
  const div = document.createElement('div');
  div.innerText = event.data;
  document.body.append(div);
})

// 点击发送按钮,将输入框中的内容发送给服务器
const input = document.querySelector('input');
const btn = document.querySelector('button');
btn.onclick = () => {
  ws.send(input.value);
  input.value = '';
}
复制代码

Efecto

图片

sala de chat sencilla

Use Socket.IO en su lugar

La biblioteca ws es una implementación de bajo nivel, que es relativamente simple.

La capa inferior de otra biblioteca, Socket.IO, usa ws y mejora sus funciones para brindar más capacidades.

Comparado con ws, Socket.IO puede hacer:

  1. 如果浏览器不支持 WebSocket,回退为 HTTP 长轮询方案来模拟 WebSocket( WebSocket 于 2011 年完成 RFC,已经很久了,目前来说主流浏览器都已经支持 WebSocket 了,还不支持 WebSocket 的浏览器是屑);

  2. 使用心跳包机制实现了自动重连。

  3. 包缓存。断连时发送数据,会将数据保存下来,等重新连接后再发送;

  4. 自定义事件支持;

  5. 广播;

相比自己去一个个实现,使用流行的轮子可能是更好的选择。

我们将前面的功能用 Socket.IO 实现一下。

服务端:

import { Server } from "socket.io";

// socket.io v3.x 开始默认不允许跨域,需要在配置显式设置为允许跨域
const io = new Server(6060, { cors: { origin"*" } });

io.on("connection"(socket) => {
  // 新客户端连接时,广播
  io.emit("chat"`有人进入聊天室,当前聊天室人数:${io.engine.clientsCount}`);

  // 广播任何客户端发送的消息
  socket.on("chat"(data) => {
    io.emit("chat", data);
  });

  // 当有客户端退出时,广播
  socket.on("disconnect"() => {
    io.emit("chat"`有人退出了聊天室,当前聊天室人数:${io.engine.clientsCount}`);
  });
});
复制代码

需要特别注意的是,Socket.IO 的 v3.x 版本开始,默认不允许跨域,需要在配置显式设置为允许跨域。

客户端:

const socket = io('ws://localhost:6060');

socket.on('chat'(data) => {
  const div = document.createElement('div');
  div.innerText = data;
  document.body.append(div);
})

// 点击发送按钮,将输入框中的内容发送给服务器
const input = document.querySelector('input');
const btn = document.querySelector('button');
btn.onclick = () => {
  console.log('发送');
  socket.emit('chat', input.value);
  input.value = '';
}
复制代码

Socket.IO 优点是实现了生产环境需要的底层非业务能力,让我们能更心无旁骛地去编写业务代码。

缺点是丢失了灵活性。因为做了定制化,所以需要配套使用 Socket.IO 的客户端和服务端库的包,某种意义脱离了网络协议标准。在出现跨语言(比如前端是 JS,后端是 Java)的场景时,需要提供对应的语言的 Socket.IO 实现。

demo

demo 已经放到 github 上了,使用方法在 README.md 中有说明。

github.com/F-star/webs…

结尾

本文演示了 WebSocket  简易的聊天室功能是如何实现的,希望对你有所帮助。

我是前端西瓜哥,欢迎关注我,学习更多前端知识。

Supongo que te gusta

Origin juejin.im/post/7192927482662617145
Recomendado
Clasificación