Getting Started with WebSockets: A Simple Chat Room

This article was first published on my public account: Front-end watermelon brother

Hello everyone, I am the front-end watermelon brother. Today we use WebSocket to implement a simple chat room.

WebSocket is an application layer protocol, somewhat similar to HTTP. But unlike HTTP, it supports true full-duplex, that is, not only the client can actively send messages to the server, but the server can also actively send messages to the client.

Especially the latter, let us no longer implement server-side notifications based on the inefficient way of HTTP long polling or short polling. Compared with HTTP, WebSocket's server push is lighter and can reduce the pressure on the server.

Server

nodejs does not provide a native WebSocket module. If you want to implement it, you need to implement it based on the net module and according to the WebSocket standard.

Because the implementation is very complicated, I chose to use the third library ws directly.

yarn add ws
复制代码

Similar to native http modules of nodejs, the ws library supports WebSocket server or client, and provides low-level APIs.

Let's implement the server code first:

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}`);
    });
  });
});
复制代码

Whenever a client makes a websocket connection, it will trigger the connectionevent , and then get a ws object.

This ws object represents the connection between a certain client and the server . We can use it to receive messages from the corresponding client, and let the server actively push messages to the specified client.

The newly created ws object will be saved to the wsServer.clients collection when the connection is established, and removed after the connection is closed. So we can use this wsServer.clients to broadcast and implement the chat room function.

client

The client uses the native WebSocket object to make a WebSocket connection with the server.

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 = '';
}
复制代码

Effect

图片

simple chat room

Use Socket.IO instead

The ws library is a low-level implementation, which is relatively simple.

The bottom layer of another library, Socket.IO, uses ws and enhances its functions to provide more capabilities.

Compared with ws, Socket.IO can do:

  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  简易的聊天室功能是如何实现的,希望对你有所帮助。

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

Guess you like

Origin juejin.im/post/7192927482662617145