JianghuJS- SocketIO

12002

1. Background

  • Description of socket.io

Socket.io is a WebSocket library that includes client-side JavaScript and server-side Node.js. Its goal is to build real-time applications that can be used across different browsers and mobile devices.

It automatically selects the best method for implementing real-time web applications from various options such as WebSocket, AJAX long polling, Iframe streaming, etc., based on the browser, making it very convenient and user-friendly, with support for browsers as low as IE5.5.

  • Why use socket.io

The main reason for using socket.io is that it provides a simple and flexible way to achieve real-time bidirectional communication, especially in building applications that require real-time capabilities. Socket.io offers many advantages:

  1. Real-time: Socket.io is based on the WebSocket protocol, which can establish a persistent bidirectional connection between the client and server, achieving very high real-time performance, suitable for scenarios requiring instant communication, such as chat applications and real-time collaboration tools.

  2. Cross-platform compatibility: Socket.io can run on different browsers and mobile devices, providing cross-platform compatibility, allowing developers to focus less on the differences between platforms.

  3. Event-driven model: Socket.io uses an event-driven programming model, communicating through triggering and listening to events. This model makes the code clearer and easier to understand, and it can conveniently handle asynchronous operations in different scenarios.

  4. Flexibility and scalability: Socket.io has good flexibility and scalability, easily accommodating various real-time communication needs. Additionally, it supports multiple rooms and namespaces, allowing developers to control the scope of communication more precisely.

  5. Simplified real-time application development: The existence of socket.io simplifies the development process of real-time applications. Developers can focus more on business logic without worrying too much about the underlying communication details, which helps improve development efficiency.

  6. Adaptive transmission methods: Socket.io can automatically select the best transmission method based on browser and network conditions, including WebSocket, AJAX long polling, Iframe streaming, etc. This ensures reliable real-time communication services in various network environments.

2. Features

  • Implemented functionalities
  1. Real-time analytics: By pushing data in real-time, it enables real-time analysis for applications such as real-time counters, chart displays, logs, etc.

  2. Real-time communication and chat: Socket.io provides a simple API that makes the development of real-time communication and chat applications easy, allowing a real-time chat application to be implemented in just a few lines of code.

  3. Binary stream transmission: Starting from version 1.0, socket.io supports the transmission of any form of binary files, such as images, videos, audio, etc., enabling the transfer of various types of files in real-time communication.

  4. Document collaboration: Socket.io can be used to implement multi-user collaborative editing of a document, where each user's modifications can be synchronized in real-time to other users, achieving collaborative document editing.

3. Usage

  • Server-side

  • Configure jiangHuConfig to enable socket:

// config.default.js

jiangHuConfig: {
  enableSocket: true
}
  • Configure socketIO configuration information:
// config.default.js at the same level as jianghuConfig
    socketIO: {
      path: `/${appId}/socket.io`,
      serveClient: true,
      connectTimeout: 45000,
      // In multi-work mode, enable redis adapter
      // redis: {
      //   host: "127.0.0.1",
      //   port: "6379",
      //   // password: '',
      //   db: 0,
      // },
    },
  • Send socket messages:
const { socketIO } = this.app;
socketIO.to(toSocketId).emit(resourcePath, socketBody);
  • Client-side

  • Initialize socket client:

function init() {
      const requestBody = {
        packageId,
        packageType: "socketRequest",
        deviceId: socket.deviceId,
        status: null,
        timestamp: new Date().toISOString(),
        appData: {
          appId: window.appInfo.appId,
          pageId: "socket",
          actionId: "connect",
          authToken: socket.authToken,
          actionData: {
            socketId,
          },
        },
      };
      try {
        socket.client = io("/", {
          path: `/${window.appInfo.appId}/socket.io`,
          auth: requestBody,
          closeOnBeforeunload: true,
          transports: ["websocket"],
          forceNew: true,
          timeout: 5000,
          secure: false, // Whether to support SSL/TLS
        });
      } catch (e) {
        console.error(e);
      }

}
  • Register client event listeners:
socket.client.on("resource", async (message) => {
        console.log("==== [socket channel.resource]", JSON.stringify(message));
        const { appId, pageId, actionId } = message.appData;
        socket.packageId = message.packageId;
        // Authentication successful
        if (pageId === "socket" && actionId === "connect") {
          // Each disconnection goes through the authentication process again; be careful not to confuse the logic of code=100
          // Set online status
          socket.online = true;
          socket.loadFinish = true;
          console.log("socket.hasDisconnectOrError :: " + socket.hasDisconnectOrError)
          socket.onReConnect(socket.hasDisconnectOrError)
        } else {
          socket.receiveSocketMsg(message.appData, message.packageId);
          if (socket.packageListeners[message.packageId]) {
            const { callback } = socket.packageListeners[message.packageId];
            callback(message);
          }
        }
      });
      socket.client.on("connect", (message) => {
        console.log("==== [socket channel.onConnect]", message);
      });
      socket.client.on("connect_timeout", (message) => {
        console.log("==== [socket channel.connect_timeout]", message);
      });
      socket.client.on("connect_error", (message) => {
        console.log("==== [socket channel.onError]", message);
        socket.hasDisconnectOrError = true;
        socket.online = false;
      });
      socket.client.on("disconnect", (message) => {
        console.log("==== [socket channel.disconnect]", message);
        socket.online = false;
        socket.hasDisconnectOrError = true;
      });
      socket.client.on("reconnect", (message) => {
        socket.hasDisconnectOrError = true;
        console.log("==== [socket channel.onReconnect]", message);
      });
      socket.client.on("reconnect_attempt", (message) => {
        console.log("==== [socket channel.onReconnectAttempt]", message);
      });
      socket.client.on("reconnect_failed", (message) => {
        console.log("==== [socket channel.onReconnectFailed]", message);
      });
      socket.client.on("reconnect_error", (message) => {
        console.log("==== [socket channel.onReconnectError]", message);
      });
      socket.client.on("ping", (message) => {
        // Heartbeat request
        // callback_onIMPing
        console.log("==== [socket channel.onPing]", message);
      });
      socket.client.on("pong", (message) => {
        // Heartbeat response
        // callback_onIMPong
        console.log("==== [socket channel.onPong]", message);
      });
  • Add socket client reconnection logic
// Check connection status every 5 seconds; if disconnected, attempt to reconnect
setInterval(() => {
  if (!socket.connected) {
    this.init()
  }
}, 5000)
  • Send socket messages:
const packageId = `${Date.now()}_${_.random(1000000, 9999999)}`;
      const requestBody = {
        packageId,
        packageType: "socketForward",
        deviceId: socket.deviceId,
        status: null,
        timestamp: new Date().toISOString(),
        appData: {
          appId: window.appInfo.appId,
          pageId: "socket",
          actionId,
          authToken: socket.authToken,
          actionData,
        },
      };
      socket.client.emit("resource", requestBody);