Before we introduce WebSocket, let’s talk about how to implement two-way Web communication in the past

Let’s talk about communication modes

  • Simplex: Data can be transmitted in only one direction. For example, the BP machine
  • Half duplex: Allows data to be transmitted in two directions, but allows data to be transmitted in one direction at a time. For example: walkie-talkie, telegraph
  • Full-duplex: simultaneous transmission in two directions. It is the combination of simplex communication and requires that the sending device and the receiving device have independent receiving and sending capabilities. Example: mobile phone

Historical review

The HTTP protocol has a flaw: communication can only be initiated by the client. For example, if we want to know today’s weather, the client can only send a request to the server, and the server returns the query result. The HTTP protocol does not allow the server to actively push information to the client. The nature of this one-way request makes it very difficult for the client to know if the server has continuous state changes. Before the WebSocket protocol, there were three ways to achieve two-way communication: polling, long-polling, and iframe streaming.

Polling (polling)

Polling is an ongoing connection between the client and the server, asking questions once in a while. The disadvantage is also obvious: the number of connections can be large, with one receiving and one sending. In addition, Http headers are sent each time a request is sent, which can consume traffic and CPU utilization.

  • Advantages: Simple implementation without too many changes
  • Disadvantages: The polling interval is too long, so users cannot receive the updated data in time. If the polling interval is too short, too many query requests will be made, which will increase the burden on the server

The instance

1.index.html

<! --index.html-->

      
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/[email protected]/dist/axios.min.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
    <title>polling</title>
</head>
<body>
<div id="app">
    <button @click="polling">HTTP polling</button>
    <button @click="stopPolling">Stop polling</button>
    <p>{{time}}</p>
</div>
<script>
    window.onload=function(){
        let vm=new Vue({
            el:'#app'.data: {time: ' '.timer: null
            },
            mounted() {

            },
            methods: {
                polling() {
                    this.stopPolling()
                    this.timer = setInterval(this.getTime, 1000)
                },
                stopPolling() {
                    clearInterval(this.timer)
                    this.timer = null
                },
                getTime(){
                    window.axios.get('/polling').then(res= > {
                        this.time = res.data
                    })
                }
            }
        });
    };
</script>
</body>
</html>
Copy the code

2.server.js

// server.js
const port = 8001
let path = require('path');
let express = require('express'), // Introduce the Express module
   app = express(),
   server = require('http').createServer(app);
app.use(express.static(path.join(__dirname, 'static'))); // Specify the location of the static HTML file
app.get('/polling'.function(req,res){
    res.end(new Date().toLocaleString());
});
server.listen(port);
server.setTimeout(0);   // Set no timeout, so the server does not actively close the connection
console.log('server started'.'http://127.0.0.1:' + port);
Copy the code

3. The renderings

Long polling (long-polling)

Long polling is an improved version of polling, in which the client sends HTTP to the server to see if there is a new message, and if there is no new message, it waits. When a new message is received, it is returned to the client. To some extent, the network bandwidth and CPU utilization problems are reduced. HTTP packets contain a large amount of header data (usually more than 400 bytes), but only a small amount of data (sometimes only about 10 bytes) is needed by the server. Therefore, such packets are transmitted periodically on the network, which inevitably wastes network bandwidth.

  • Advantages: Polling has been optimized, with better timeliness
  • Disadvantages: Maintaining connections consumes resources; Server did not return valid data, program timed out.

The instance

1.index.html

<! --index.html-->

      
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/[email protected]/dist/axios.min.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
    <title>long-polling</title>
</head>
<body>
<div id="app">
    <button @click="longPolling">HTTP long polling</button>
    <button @click="stopPolling">Stop polling</button>
    <p>{{time}}</p>
</div>
<script>
    window.onload=function(){
        let vm=new Vue({
            el:'#app'.data: {time: ' '.timer: null
            },
            methods: {
                stopPolling() {
                    this.timer = null
                },
                longPolling() {
                    if(!this.timer){
                        this.timer = true
                        this.getTime()
                    }
                },
                getTime(){
                    window.axios.get('/longPolling', {timeout: 5000}).then(res= > {
                        this.time = res.data
                        this.timer && this.getTime()
                    }).catch(err= > {
                        console.log(err)
                        this.timer && this.getTime()
                    })
                }
            }
        });
    };
</script>
</body>
</html>

Copy the code

2.server.js

// server.js
const port = 8001
let path = require('path');
let express = require('express'), // Introduce the Express module
   app = express(),
   server = require('http').createServer(app);
app.use(express.static(path.join(__dirname, 'static'))); // Specify the location of the static HTML file
app.get('/longPolling'.function(req,res){
    setTimeout(_= > {
        res.end(new Date().toLocaleString());
    }, 1000)}); server.listen(port); server.setTimeout(0);   // Set no timeout, so the server does not actively close the connection
console.log('server started'.'http://127.0.0.1:' + port);
Copy the code

3. The renderings

A long connection

Iframe Streaming

The iframe streaming method inserts a hidden IFrame into the page, using its SRC property to create a long connection between the server and the client, and the server transmits data (usually HTML, with javascript to insert the information) to the iframe to update the page in real time.

  • Advantages: Messages can arrive in real time; Browser compatibility
  • Disadvantages: Server maintenance of a long connection will increase overhead; If ifame. Srec is not set dynamically, Internet Explorer, Chrome, and Firefox will display a message indicating that the loading is incomplete and the icon will rotate continuously, as shown in the following two figures

The instance

1.index.html

<! --index.html-->

      
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>longConnection</title>
</head>
<body>
<div>
    <button onclick="longConnection()">Long HTTP connection</button>
    <button onclick="stopLongConnection()">Disabling long Connections</button>
    <p id="longConnection"></p>
    <iframe id="iframe" src="" style="display:none"></iframe>
</div>
<script>
    var iframe = document.getElementById('iframe')
    function longConnection() {
        iframe.src='/longConnection2'
        console.log(iframe)
    }
    function stopLongConnection() {
        iframe.src='/'
    }
</script>
</body>
</html>
Copy the code

2.server.js

// server.js
const port = 8001
let path = require('path');
let express = require('express'), // Introduce the Express module
   app = express(),
   server = require('http').createServer(app);
app.use(express.static(path.join(__dirname, 'static'))); // Specify the location of the static HTML file
app.get('/longConnection2'.function(req,res){
    let count = 0
    let longConnectionTimer = null
    clearInterval(longConnectionTimer)
    longConnectionTimer = setInterval(_= > {
        if (res.socket._handle) {
            console.log('longConnection2-' + count++)
            let date = new Date().toLocaleString()
            res.write(`
           <script type="text/javascript">
             parent.document.getElementById('longConnection').innerHTML = "${date}"; // Change the parent window DOM element </script> ')}else {
            console.log('longConnection2-stop')
            clearInterval(longConnectionTimer)
            longConnectionTimer = null}},1000)}); server.listen(port); server.setTimeout(0);   // Set no timeout, so the server does not actively close the connection
console.log('server started'.'http://127.0.0.1:' + port);
Copy the code

3. The renderings

EventSource (SSE-server-sent Events, does not count as history technology, falls under H5 scope)

The official name of EventSource should be Server-sent Events (SSE). EventSource is a simple single communication based on HTTP protocol, realizing the process of Server push. The client cannot send data to the Server through EventSource. Although it can not achieve two-way communication, it has some advantages in functional design, such as automatic reconnection, event-ids, and the ability to send random events (WebSocket can be reconnected through third-party libraries such as socket. IO). The instance

1.index.html

<! --index.html-->

      
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
    <title>polling</title>
</head>
<body>
<div id="app">
    <button @click="longConnection">Long HTTP connection</button>
    <button @click="stopLongConnection">Disabling long Connections</button>
    <p>{{time}}</p>
</div>
<script>
    window.onload=function(){
        let vm=new Vue({
            el:'#app'.data: {time: ' '.eventSource: null
            },
            methods: {
                stopLongConnection() {
                   this.close()
                },
                longConnection() {
                    this.getTime()
                },
                getTime(){
                    // Instantiate the EventSource object and specify a URL
                    this.eventSource = new EventSource('/longConnection'); // Use the addEventListener() method to listen for events
                    console.log("Current state 0".this.eventSource.readyState);
                    this.eventSource.onopen = this.onopen
                    this.eventSource.onmessage = this.onmessage
                    this.eventSource.onerror = this.onerror
                },
                onopen(){
                    console.log("Link successful.");
                    console.log("Current State 1".this.eventSource.readyState);
                },
                onmessage(res){
                    this.time = res.data
                },
                onerror(err){
                    console.log(err)
                },
                close(){
                    this.eventSource && this.eventSource.close()
                    console.log("Current State 2".this.eventSource.readyState); }}}); };</script>
</body>
</html>
Copy the code

2.server.js

// server.js
const port = 8001
let path = require('path');
let express = require('express'), // Introduce the Express module
   app = express(),
   server = require('http').createServer(app);
app.use(express.static(path.join(__dirname, 'static'))); // Specify the location of the static HTML file
app.get('/longConnection'.function(req,res){
    let count = 0
    let longConnectionTimer = null
    clearInterval(longConnectionTimer)
    res.writeHead(200, {
        'Content-Type': "text/event-stream".'Cache-Control': 'no-cache'.'Connection': 'keep-alive'
    })
    longConnectionTimer = setInterval(_= > {
        if(res.socket._handle){
            console.log('longConnection-' + count++)
            const data = { timeStamp: Date.now() };
            res.write(`data: The ${new Date().toLocaleString()}\n\n`);
        } else {
            console.log('longConnection-stop')
            clearInterval(longConnectionTimer)
            longConnectionTimer = null
            res.end('stop'); }},1000)}); server.listen(port); server.setTimeout(0);   // Set no timeout, so the server does not actively close the connection
console.log('server started'.'http://127.0.0.1:' + port);
Copy the code

3. The renderings

What it does: Because of the limitations of single communication, EventSource is well suited for scenarios where back-end data updates are frequent and require high real-time performance without requiring client to communicate with the server. For example, to implement scenarios like stock quotes, news feeds, and real-time weather that only require the server to send messages to the client. The fact that EventSource is easier to use is also a plus.

Webpack-hot-middleware for EventSource

  • advantages
    1. Based on existing HTTP protocol, the implementation is simple
    2. Automatically reconnection after disconnection, and reconnection timeout can be set
    3. Dispatch any event
    4. Cross – domain and have corresponding security filtering
  • disadvantages
    1. Only one-way communication, the server pushes events to the client
    2. The event stream protocol can only transmit UTF-8 data and does not support binary streams.
    3. Compatibility is not high, IE and Edge currently do not support EventSource
    4. The server needs to maintain HTTP connections, consuming certain resources

The readyState property of the EventSource instance, indicating the current state of the connection. This property is read-only and can take the following values.

  • 0: equivalent to the constant eventsource. CONNECTING, indicating that the connection has not been established or is being reconnected.
  • 1: equivalent to the constant eventsource. OPEN, indicating that the connection has been established and data can be accepted.
  • 2: equivalent to the constant eventsource. CLOSED, which indicates that the connection is CLOSED and will not be reconnected.

Note:

  1. EventSource is a server-side push technology.
  2. Generally speaking, web pages get data from the server by sending requests, and the server push technology allows the server to send data to the client at any time.
  3. EventSource is based on HTTP long links
    • The client needs to create an EventSource object with the server URI as the parameter
    • The content-type of the response packet returned by the server must be text or event-stream.

Flash Socket

Embedded in the page is a Flash program using the Socket class JavaScript by calling the Socket interface provided by the Flash program to communicate with the Socket interface of the server. JavaScript controls the display of the page after receiving the information sent by the server.

  • Advantages: real instant communication, rather than pseudo instant.
  • Disadvantages: Flash plug-in must be installed on the client; If the protocol is not HTTP, the firewall cannot be automatically traversed.
  • Example: Online interactive games.

==Flash don’t understand also don’t say too much, say more is made up ==

Above demo source address: github.com/liliuzhu/pe…

WebSocket

WebSocket is a protocol for full duplex communication over a single TCP connection provided by HTML5.

WebSocket makes it easier to exchange data between the client and the server, allowing the server to actively push data to the client. In the WebSocket API, the browser and server only need to complete a handshake to create a persistent connection and two-way data transfer.

In the WebSocket API, the browser and the server only need to do a handshake, and then a fast channel is formed between the browser and the server. Data can be transmitted directly between the two.

The WebSocket protocol defined by HTML5 can save server resources and bandwidth better, and can communicate in a more real-time manner. Addresses many of the drawbacks of polling and other long connections.

How to use WebSocket

// WebSocket client native API
var Socket = new WebSocket('ws://localhost:8080') // The WebSocket object is used as a constructor to create a new WebSocket instance.
Socket.onopen = function(){} // Triggered when the connection is established
Socket.onclose = function(){}  // Triggered when the connection is closed
Socket.onmessage = function(){} // Triggered when the client receives data from the server
Socket.send('data') // The send() method of the instance object is used to send data to the server
Socket.close() // Close the connection
socket.onerror = function(){} // Triggered when a communication error occurs
Copy the code

Socket.readyState indicates the connection state, which can be the following values

  • 0 – Indicates that the connection is not established.
  • 1 – Indicates that the connection is established and communication can be performed.
  • 2 – Indicates that the connection is being closed.
  • 3 – Indicates that the connection is closed or cannot be opened.

Note: Websocket uses the Uniform Resource Identifier of WS or WSS, similar to HTTPS, where WSS stands for Websocket over TLS

Websockets use the same TCP port as HTTP and can bypass most firewall restrictions. By default, Websocket uses port 80. When running over TLS, port 443 is used by default.

Although WebSocketServer can use other ports, a unified port is the preferred option

// The server data can be either text or binary (bloB objects or Arraybuffer objects).
ws.onmessage = function(event){
  if(typeof event.data === String) {
    console.log("Received data string");
  }

  if(event.data instanceof ArrayBuffer) {var buffer = event.data;
    console.log("Received arraybuffer"); }}// In addition to dynamically determining the received data type, you can also explicitly specify the received binary data type using the binaryType attribute.
// BloB data is received
ws.binaryType = "blob";
ws.onmessage = function(e) {
  console.log(e.data.size);
};

// Receive ArrayBuffer data
ws.binaryType = "arraybuffer";
ws.onmessage = function(e) {
  console.log(e.data.byteLength);
};

// Send an example of Blob objects.
var file = document
  .querySelector('input[type="file"]')
  .files[0];
ws.send(file);

// Send an example of an ArrayBuffer object.
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0.0.400.320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
  binary[i] = img.data[i];
}
ws.send(binary.buffer);

// The bufferedAmount property of the instance object, indicating how many bytes of binary data remain unsent. It can be used to determine whether the transmission is complete.
var data = new ArrayBuffer(10000000);
socket.send(data);
if (socket.bufferedAmount === 0) {
  // Send complete
} else {
  // Send is not finished yet
}
Copy the code

WebSocket vs. EventSource

EventSource, like WebSocket, is new to HTML5, but there are big differences in positioning.

  1. WebSocket is TCP based, and EventSource is HTTP based.
  2. EventSource is one-way communication, while Websocket is two-way communication.
  3. EventSource can only send text, while WebSocket supports sending binary data.
  4. EventSource is simpler to implement than Websocket.
  5. EventSource has the ability to automatically reconnect (without third parties) and send random events.
  6. Websocket is too heavy and EventSource is lighter.
  7. Websocket can be cross-domain, and cross-domain EventSource over HTTP requires the server to set the request header.

The WebSocket protocol is essentially a TCP – based protocol.

In order to establish a WebSocket connection, the client browser first sends an HTTP request to the server. This request is different from the usual HTTP request and contains some additional header information. The additional header “Upgrade:WebSocket” indicates that this is an HTTP request for a protocol Upgrade. Server-side parsing these additional header information generated response is then returned to the client, the client and the server connection is established, the two sides can through this connection channel information of freedom, and the connection will continue to exist until the client or server side one side take the initiative to close the connection.

Websocket is a new protocol that has little to do with HTTP and is designed to be compatible with the existing browser handshake specification, which means it is a supplement to HTTP.

No nonsense on the case

Github.com/liliuzhu/pe…

Comparison of Web real-time push technologies

way type The technical implementation advantages disadvantages Applicable scenario
Polling Polling The client ⇌ server Client loop requests 1, simple implementation 2, support cross-domain 1. Waste of bandwidth and server resources. 2. Most of a request information is useless (complete HTTP header information) Suitable for small applications
Long Polling Long Polling The client ⇌ server The server holds the connection until it has data or times out, reducing the number of repeated requests 1, simple implementation 2, do not frequently send requests 3, save traffic 4, low latency (1) The server holds the connection and consumes resources. (2) A request for information is mostly useless WebQQ, Hi web version, Facebook IM
Long connection iframe Server ⇌ client Embed a hidden iframe in the page, set the SRC attribute of the IFrame to a request for a long connection, and the server can stream data to the client. 1, real-time data delivery 2, do not send useless requests, one link, multiple “push” 2. The connection status cannot be accurately known. 3 Gmail chat
EventSource Server and client new EventSource() 1. Simple implementation based on existing HTTP protocol. 2. Automatic reconnection after disconnection, and reconnection timeout can be set. 3 2. The event stream protocol can only transmit UTF-8 data, but does not support binary streams. 4. Poor compatibility, IE and Edge currently do not support all EventSource servers need to maintain HTTP connections, consuming certain resources Stock quotes, news feeds, real-time weather
WebSocket Server ⇌ client new WebSocket() 1, support two-way communication, real-time stronger 2, can send binary files 3, reduce traffic 2. Disconnection and reconnection are not supported Online games, banking interactions and payments

To sum up: Websocket protocol not only solves the passivity of the SERVER in HTTP protocol, that is, communication can only be initiated by the client, but also solves the problem of delayed data synchronization and brings obvious performance advantages. Therefore, Websocket is an ideal solution for real-time Web push technology. However, if you want to be compatible with browsers of lower versions, Consider polling.

WebSocket on the server

IO, websocket-node, WS, nodejs-webSocket, and many more

  1. Socket. IO: Socket. IO is a WebSocket library that includes client-side JS and server-side NodeJS. It will automatically according to the browser from WebSocket, AJAX long polling, Iframe stream and so on a variety of ways to choose the best way to achieve real-time network applications (do not support WebSocket will be degraded to AJAX polling), very convenient and user-friendly, compatibility is very good, support the browser as low as IE5.5. Details differences and compatibility issues are shielded to achieve cross-browser/cross-device two-way data communication.

  2. Ws: Unlike the socket. IO module, WS is a pure Websocket module that does not provide upward compatibility and does not require additional JS files to be hung on the client side. The browser’s native Websocket API can be used to communicate without the need for secondary encapsulation on the client side.

reference

  1. Blog.csdn.net/yhb241/arti…
  2. www.tuicool.com/articles/FF…
  3. Developer.mozilla.org/zh-CN/docs/…
  4. www.jianshu.com/p/958eba34a…
  5. www.runoob.com/html/html5-…

This post was originally posted on liliuzhu. Gize. IO /blog