Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)

技术讨论群【522121825】

前言

        虽然写了好几篇关于 vue-socket.io 的文章,但是也还是对底层实现原理模糊不清,甚至对Socket.io、Vue-socket.io、socket.io-client 的关系理不清楚。今天,重新阅读源码,研读官网说明,一字一句解析Socket.io的底层实现原理,让你彻底弄懂如何实现即时聊天,技术之间的关系。

vue-socket.io

        先说说这个我们最熟悉的技术吧(这个没有官网哈,我们一直看到的是socket.io 的官网)。

GitHub - MetinSeylan/Vue-Socket.io: Socket.io implementation for Vuejs and Vuex Socket.io implementation for Vuejs and Vuex. Contribute to MetinSeylan/Vue-Socket.io development by creating an account on GitHub.icon-default.png?t=N7T8https://github.com/MetinSeylan/Vue-Socket.ioSocket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第1张图片

        Vue-Socket.io是Vuejs的Socket.io集成,易于使用,支持Vuex和组件级套接字管理。说白了,就是基于Socket.io的Vue版本,底层实现了 vuex 的使用。

        在vue-socket.io源码中,可以清晰看到,第一行,便是引入了 socket.io-client。现在你不知道 socket.io-client 没关系,继续往下看。

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第2张图片

         我们 new 的是VueSocketIO,传入的配置就支持 vuex,这就是Vue-Socket.io。Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第3张图片

 Socket.io

Socket.IOicon-default.png?t=N7T8https://socket.io/zh-CN/Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第4张图片

         这个才是我们学习的重点,所有技术的核心,底层实现都源于 Socket.io。接下来,我们将重点介绍socket.io、socket.io-client、还有服务端,究竟是怎么实现的。

        Socket.IO 是一个库,可以在客户端和服务器之间实现 低延迟双向 和 基于事件的 通信,支持的服务端语言很多,Node、Java、Python、Golang,很多同学问能不能在Java上使用,是可以的哦。

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第5张图片

         很多人都将Socket.io 与Websocket 进行混淆,官网中页描述了两者的关系,因此,socket.io  是不能直接连接 websocket 服务的。

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第6张图片

 Engine.IO

        Engine.IO 负责建立服务器和客户端之间的低级连接,负责连接的建立、传输、短线重连等机制。

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第7张图片

 Socket.io

        Socket.IO 通过 Engine.IO 连接提供了一些附加功能,这是实现通信的核心,通过提供的API实现响应功能,包括数据缓冲、广播、房间、命名空间等。这是第一次见到 socket.io-client 库。

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第8张图片

内存占用与性能优化 

        socket.io 提供了完整的垃圾回收机制,并对服务器消耗做了分析,如果对服务端并发要求高的,一定仔细阅读相关章节

内存占用 | Socket.IOSocket.IO服务器消耗的资源主要取决于:icon-default.png?t=N7T8https://socket.io/zh-CN/docs/v4/memory-usage/

性能优化 | Socket.IO以下是一些提高 Socket.IO 服务器性能的技巧:icon-default.png?t=N7T8https://socket.io/zh-CN/docs/v4/performance-tuning/

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第9张图片

socket.io-client

        至此,我们应该已经非常清晰知道,socket.io-client 其实就是Socket.io 的客户端核心库

// the following forms are similar
const socket = io("https://server-domain.com");
const socket = io("wss://server-domain.com");
const socket = io("server-domain.com"); // only in the browser when the page is served over https (will not work in Node.js)

        如果客户端与服务端不同源,则需要开启服务端 跨域资源共享 CORS

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第10张图片

         也是我们常见的 Node服务器处理 socket.io 跨域

import { createServer } from "http";
import { Server } from "socket.io";

const httpServer = createServer();
const io = new Server(httpServer, {
  cors: {
    // 如果需要支持多源,则配置成: origin:['','']
    origin: "https://example.com",
  }
});

        客户端 Socket.io-client 基本上介绍完成了

Socket.io 服务端

        socket.io 支持我们应用不同的方式搭建服务端应用,

        Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第11张图片

        好多人好奇,理论上,我们连接的应该是 ws / wss 的地址呀,写http多少有误解,那么,能不能实现呢?下面是最简单的 socket.io 原生的服务端,监听了 5000 端口,你能说这是 http 的嘛?还是websocket的?

const { Server } = require("socket.io");

const io = new Server({
  allowEIO3: true,
  cors: {
    origin: ["http://localhost:3000", "http://127.0.0.1:3000"],
    methods: ["GET", "POST"],
    credentials: true,
  },
});

io.on("connection", (socket) => {
  // ...
  console.log("用户连接");
});

io.listen(5000);
let httpsocket = io("http://localhost:5000");
let wssocket = io("ws://localhost:5000");

        实际上,两个都是能用的,不管是 http、express还是原生,源码中,为我们兼容了不同的方式:

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第12张图片

        官网中,描述了Socket.io 的底层实现原理,http长轮询、websocket、webtransport,如果无法建立 WebSocket 连接,连接将回退到 HTTP 长轮询。如果自己底层都不支持 http ws地址连接,又何来的回退http长轮询呢?

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第13张图片         服务端中间件,这里不详细说了,跟Express的中间件类似,可以在 io 执行 connect 之前,进行数据处理:

io.use((socket, next) => {
  next();
});

io.use((socket, next) => {
  next(new Error("thou shall not pass"));
});

io.use((socket, next) => {
  // not executed, since the previous middleware has returned an error
  next();
});

Vue-socket.io与Socket.io-client的关系

        通过上面的分析,应该更加清晰看出两者的关系了吧,vue-socket.io  是socket.io 的集成封装,而socket.io-client 是socket.io 的客户端核心库。在实际开发中如何选择?如果你需要vuex的事件监听,或者想更简单的使用,推荐使用vue-socket.io,但是也有些弊端,正如我的vue3连接文章中,我们为什么要使用 socket.io 进行事件通信?

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第14张图片

        我们使用Vue-socket.io 与 socket.io-client 进行通信,对比一下两个对象:

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第15张图片

 socket.io-client  对象:Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第16张图片

         其中不难看出,Vue-socket.io 的对象 是emitter、io、listener构成,而emitter是拓展的Vuex

Socket.IO 实现原理(一篇文章让你彻底弄懂即时聊天技术)_第17张图片

         真正用于实现通信的是io,因此,我们在vue2 中,使用 this.$socket.emit() 发送消息外,还能用 socket.io.emit() 进行消息通信,这也就是vuex3中得出并实现的底层原理

Vue3中Socket.io-client 的使用

        通过上的对比分析,在vue3中,使用 socket.io-client 应该是最适合的,下面实现:

// 新建 socket.js 文件
import { io } from "socket.io-client";

class Socket {
  constructor() {
    this.connected = false;

    this.eventHandle();

    const socket = io("ws://localhost:5000");

    this.socket = socket;

    socket.on("connect", () => {
      this.connected = true;
    });

    socket.on("disconnect", () => {
      this.connected = false;
    });

    // 使用事件监听器的形式,才能保证每次监听到 welcome 事件,都会触发回调
    socket.on("welcome", (data) => this.emit("welcome", data));
  }

  login(data) {
    // 可以对 socket.io 连接状态进行判断、重连等操作
    this.socket.emit("login", data);
  }

  eventHandle() {
    this.obj = {};
    this.on = function (name, fn) {
      if (!this.obj[name]) {
        this.obj[name] = [];
      }
      this.obj[name].push(fn);
    };
    this.emit = function (name, val) {
      if (this.obj[name]) {
        this.obj[name].map((fn) => {
          fn(val);
        });
      }
    };
    this.off = function (name, val) {
      if (this.obj[name]) {
        if (fn) {
          let index = this.obj[name].indexOf(fn);
          if (index > -1) {
            this.obj[name].splice(index, 1);
          }
        } else {
          this.obj[name].length = 0;
          //设长度为0比obj[name] = []更优,因为如果是空数组则又开辟了一个新空间,设长度为0则不必开辟新空间
        }
      }
    };
  }
}

export const client = new Socket();

         socket.io 原生Node 实现:

// socket.io 原生搭建
const { Server } = require("socket.io");

const io = new Server({
  allowEIO3: true,
  cors: {
    origin: ["http://localhost:3000", "http://127.0.0.1:3000"],
    methods: ["GET", "POST"],
    credentials: true,
  },
});

io.on("connection", (conn) => {
  // ...
  console.log("用户连接");

  conn.on("login", (data) => {
    console.log("login", data);

    setTimeout(() => conn.emit("welcome", "服务端发送消息"), 2000);
  });
});

io.listen(5000);
// main.js
import { createApp } from "vue";
import App from "./App.vue";
import "./socket";
createApp(App).mount("#app");
// app.vue






        对比我们的这篇文章,socket.io-client在vue3中的使用,简直太简单了呀

Vue 使用 Vue-socket.io 实现即时聊天应用(Vue3连接原理分析)-CSDN博客文章浏览阅读7.4k次,点赞17次,收藏46次。总的来看,要深入了解socket的源码,知道其实现方式,基于源码,将vue3的特性结合进去_vue-socket.iohttps://blog.csdn.net/weixin_47746452/article/details/126827806?spm=1001.2014.3001.5501        结合pinia或者 vuex 的场景,应该在socket.js 中,直接进行 pinia通信就行了,也能实现类似效果,只不过不是 vuex 原生监听事件实现。

总结

        1. 我们深入了解了 Socket.io 的底层实现原理;

        2. 再次探索 Vue-Socket.io 的底层依赖;

        3. 清晰认识到 Socket.io-client 的关系;

        4. 再次构建了 Vue3 版本的socket监听实现。

你可能感兴趣的:(Socket.io,即时通信技术,vue-socket.io,socket.io,socketIO-Client,vue3使用Socket.io,vue即时通信技术,socket通信技术,web,socket)