web project polling practice

Posted by kyoru on Mon, 27 Dec 2021 03:22:05 +0100

Recently, two different methods have been used to realize instant messaging: one is polling based on timer (cooperating with the back-end within the project), and the other is two-way communication based on websocket (integrating and cooperating with the third party). Next, the basic use, advantages and disadvantages of these two different instant messaging methods will be introduced.

The first: Ajax polling

polling

  • Demand scenario: the displayed panel data needs to be refreshed in real time.
  • Implementation process: the client actively sends a request to the server, waits for a fixed period of time (usually using the setInterval function of JavaScript), and then sends the request again

    setInterval(function () {
      fetch('get-csrf')
        .then((res) => res.json())
        .then((res) => {
          console.log(res);
        });
    }, 5 * 1000);
    
  • Advantages: it is simple to implement, does not need any specific functions of the server, and can be processed only by the client. And all browsers support, good error handling system, timeout management
  • Disadvantages:

    • Waste of server and network resources: most links are invalid and duplicate
    • There is a delay in response data: the longer the time interval of setInterval is set, the more time it takes for new data on the server to reach the client, which is not scalable
    • The results of the response are not in order: because it is an asynchronous request, when the sent request does not return the result, the subsequent request is sent again. At this time, if the subsequent request returns the result earlier than the previous request, the result data returned by the previous request is outdated and invalid
  • Problem scenario: regularly request the interface every 5s vs. obtain it every 5s after the interface returns

    • The request is executed at an interval of 5s after the response, which can ensure the order of the response, but at the same time, the problem that subsequent operations will not be executed when the request does not respond needs to be considered.
    • The processing of timeout response can be added. If there is no response after a certain time, the request will be cancelled. At the same time, the timeout time should also consider other interfaces with long request time, and there is no real-time refresh function to prevent no data display after the timeout is cancelled.
    • The fetch request can be implemented by timeout+abort. Promise.race([fetch(),timout]) can also realize the function of timeout
    // After the interface returns, it is obtained at an interval of 5s 
    function getToken() {
      fetch('get-csrf')
        .then((res) => res.json())
        .then((res) => {
          console.log(res);
          setTimeout(() => {
            getToken();
          }, 5 * 1000);
        });
    }
    getToken();

Long polling

  • Implementation process: the client sends a request interface to the server, and then waits for the server to respond. The server needs to implement specific functions to allow the request to be suspended. As soon as an event occurs, the server will send a response in the suspended request and close the request. The client will use this response and open a new long-lived Ajax request to the server.
  • Compared with the above client active polling method, the server needs to have a special function to suspend the connection in the near future. In the process of project implementation, the first method is adopted for front-end personnel, which is faster and operable

    • Client code example:

      function getToken() {
        fetch('get-csrf')
          .then((res) => res.json())
          .then((res) => {
            console.log(res);
          });
      }
      getToken();
      /**
      In this long polling mode, the client calls the callback function for information processing when the readystate of XMLHttpRequest is 4 (i.e. the end of data transmission). When the readystate is 4, the data transmission ends and the connection has been closed
      **/

Other polling methods

  • Long polling of script tag & flow of iframe:

    • Implementation: the script tag is attached to the page for the script to execute. The server will suspend the connection until an event occurs, then send the script content back to the browser, and then reopen another script tag to get the next event. (src of script tag or src of iframe points to the server address)
    • There is no way to implement reliable error handling or track the status of connections, but it has cross domain functions, and there are more implementation methods, such as cors

The second is websocket

  • The first way to implement polling is based on HTTP. HTTP connection has the characteristics of passivity (it needs to be initiated by one end), stateless, one-way and non persistence. At the same time, polling has the disadvantages of data delay (time interval), repeated request waste and so on.
  • For project scenarios, such as frequent requests to update data: when the console operates 2d map, The map field of view needs to be changed (translation, zoom, rotation, etc.) the 3d map is instantly transmitted to the third-party integrated application and responds synchronously. This scenario requires higher real-time operation and frequent response. For multi-user communication, due to the way of integrating web pages, different pages are loaded through chromium. These pages are equivalent to independent browser pages, and communication and pages are required between each page Communication with third-party integrated applications is also required, so considering comprehensively, the two-way real-time communication capability of websocket can better meet the business choice.

websocket connection

  • For WebSocket connection, first perform three TCP handshakes, and then rely on the HTTP protocol for one handshake. After the handshake is successful, the data will be transmitted directly from the TCP channel, which has nothing to do with HTTP.
  • Client: when the client connects to the server, it will send an http message similar to the following to the server to upgrade the protocol

    GET ws://localhost:8080/socket.io/?UserGroup=toyGroup&EIO=3&transport=websocket HTTP/1.1
    Host: http://localhost:8080
    Connection: Upgrade
    Upgrade: websocket
    Origin: http://localhost:8000
    Sec-WebSocket-Version: 13
    Sec-WebSocket-Key: V1yj21hlXCrSK2HDuJsD9A==
    Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

    • Connection: Upgrade: indicates the protocol to be upgraded
    • Upgrade: websocket: it tells the server that it needs to switch the communication protocol to websocket
    • SEC websocket version: 13: indicates the version of websocket. If the server does not support this version, you need to return a sec websocket versionheader, which contains the version number supported by the server.
    • SEC websocket key: it is matched with the SEC websocket accept in the response header of the server. It provides basic protection, such as malicious connection or unintentional connection.

  • Server: if the server supports websocket protocol, it will switch the communication protocol to websocket and send a response message header similar to the following to the client

    HTTP/1.1 101 Switching Protocols
    Date: Mon, 20 Dec 2021 07:14:21 GMT
    Connection: upgrade
    Upgrade: websocket
    Sec-WebSocket-Accept: 8L5tW9vVu5z9vfRMglkhare9o58=

    • The returned status code is 101, indicating that it agrees with the client protocol conversion request and converts it to websocket protocol.
    • SEC websocket accept is calculated according to the SEC websocket key in the header of the client request.

websocket usage

  • Server implementation: in nodejs, ws module is used

    const WebSocket = require('ws');
    const wss = new WebSocket.Server({ port: 8080 });
    
    wss.on('connection', function connection(ws) {
      console.log('Server connection');
    
      ws.on('message', function (message) {
        // msessage defaults to Buffer
        console.log('Server receiving:', message.toString());
      });
    
      ws.send('world', { binary: false });
    });
  • Client initializes websocket instance

    import React, { useState, useEffect } from 'react';
    import styles from './index.less';
    
    interface SocketDemoProps {}
    
    const SocketDemo: React.FC<SocketDemoProps> = () => {
      const [msg, setMsg] = useState<string[]>([]);
      useEffect(() => {
        var ws = new WebSocket('ws://localhost:8080');
        ws.onopen = function () {
          msg.push('Client connection: successful');
          setMsg([...msg]);
          ws.send('hello');
        };
        ws.onmessage = function (e) {
          msg.push('Client received message:' + e.data);
          setMsg([...msg]);
        };
      }, []);
      return (
        <div className={styles.root}>
          {msg.map((item) => (
            <span>{item}</span>
          ))}
        </div>
      );
    };
    export default SocketDemo;
  • Client output

    Client connection: successful
     Client received message: world
  • Server output

    Server connection server reception: <Buffer 68 65 6c 6c 6f>// The default is Buffer. toString can be used to convert to the corresponding string. The server connects to the server and receives: hello  

Opcode of websocket

opcode defines the type of frame:
Continuous frame:

     0: Continue to the previous frame; Indicates that the type of the previous frame is exactly the same

Non control frame: it is mainly used to transmit data

    1: Text frame( UTF8)
    2: Binary frame
    3-7: Reserved frames for non control

Control frame

    8:Close frame: when off ws The link will be closed
    9:Heartbeat frame ping
    A:Heartbeat frame pong
    B-F:Reserved frames for control

websocket service setup: socket io

​ node.js provides an efficient server-side running environment. However, due to the different support of HTML5 on the browser side, in order to be compatible with all browsers, provide excellent real-time user experience, and provide programmers with the same programming experience between the client and the server, socket Io was born.

​ Socket.IO encapsulates Websocket and Node based JavaScript framework, including client JavaScript and server Node. It masks all the underlying details and makes the top-level call very simple.

In addition, socket IO also has a very important benefit. It not only supports WebSocket, but also supports many polling mechanisms and other real-time communication methods, and encapsulates a general interface. These methods include Adobe Flash Socket, Ajax long polling, Ajax multipart streaming, persistent Iframe, JSONP polling, etc. In other words, when socket When IO detects that the current environment does not support WebSocket, it can automatically select the best way to realize real-time network communication

const socket = io("127.0.0.1:8080", {
  transports: ["websocket", "polling"]  // Note: the transportation attribute can be websocket directly. If it is not set, the polling method is adopted by default
});

socket.on("connect_error", () => {
  // revert to classic upgrade
  socket.io.opts.transports = ["polling", "websocket"];
});
Features provided
  1. Reliability: the connection can still be established even if the application environment exists: agent or load balancer, personal firewall or anti-virus software
  2. Support automatic connection: unless otherwise specified, a disconnected client will reconnect to the server until the server is available. Reconnection settings

    import { io } from "socket.io-client";
    const socket = io({
      reconnection: false   // After automatic reconnection is set to false, you need to manually set reconnection
    });
    const tryReconnect = () => {
      setTimeout(() => {
        socket.io.open((err) => {
          if (err) {
            tryReconnect();
          }
        });
      }, 2000);
    }
    
    socket.io.on("close", tryReconnect);
  3. Disconnect detection: in http://Engine.io Layer implements a heartbeat mechanism, which allows the client and server to know when one of them cannot respond. This function is realized by setting the timer between the server and the client. When connecting and shaking hands, the server will actively inform the client of the heartbeat interval and timeout. The default disconnection and restart time after the browser is connected. The ws panel of chrome's Network can be viewed

    Heartbeat detection settings
    pingInterval: 25000
    pingTimeout: 5000
  4. Binary support: any serialized data structure can be used to send
  5. Cross browser support: the library even supports IE8
  6. Support reuse: in order to isolate the created concerns in the application, http://Socket.io Allows you to create multiple namespace s that have separate communication channels but will share the same underlying connections
  7. Support Room: in each namespace, you can define any number of channels, which we call "Room". You can join or leave the Room, and even broadcast messages to the specified Room.
Development version problem
  • Cross domain

    ​ socket.io v3 and socket One of IO V2 is changed to socket IO V2 supports cross domain by default, socket IO V3 requires manual support

  • socket.io v3 client connection socket Server of IO V2 version?
  • Socket. Connect the IO V3 server to the socket IO V2 client

    const io = require("socket.io")({
      allowEIO3: true // false by default
    });

More information: https://socket.io/blog/socket...

Problems in the development process of websocket

Capabilities to be provided by socket server

  • namespace and group grouping
  • State synchronization
  • Number of concurrent connections on the server

Topics: Javascript websocket