This is the 11th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021


Writing in the front

WebSocket is a network communication protocol that is required for many advanced functions.

People who are new to WebSocket ask the same question: Why do we need another protocol when we already have HTTP? What good can it do?

The simple answer is that 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 one-way nature of HTTP protocol makes it very difficult for the client to know if the server has continuous state changes. We can only use “polling” : every once in a while, we issue a query to see if the server has any new information. The most typical scenario is a chat room.

Polling is inefficient and wasteful (because you have to keep connecting, or HTTP connections are always open). So engineers have been wondering if there is a better way. That’s how WebSocket was invented.


The characteristics of the WebSocket

WebSocket protocol was born in 2008 and became an international standard in 2011. All browsers already support it.

Its biggest characteristic is that the server can take the initiative to push information to the client, the client can also take the initiative to send information to the server, is a real two-way equal dialogue, belongs to a server push technology. WebSocket allows full-duplex communication between the server and the client. For example, the HTTP protocol is a bit like sending an E-mail and having to wait for a reply; A WebSocket is like a phone call, where the server and client can simultaneously send data to each other, with a continuous open data channel between them.

Other features include:

  • (1) Based on THE TCP protocol, the implementation of the server side is relatively easy.
  • (2) It has good compatibility with HTTP protocol. The default ports are also 80 and 443, and the handshake phase uses HTTP protocol, so it is not easy to mask the handshake and can pass various HTTP proxy servers.
  • (3) The data format is relatively light, the performance overhead is small, and the communication is efficient.
  • (4) Can send text, can also send binary data.
  • (5) There is no source restriction, the client can communicate with any server, can completely replace Ajax.
  • (6) The protocol identifier isws(If encrypted, otherwisewss, corresponding to HTTPS protocol), the server URL is the URL.

The WebSocket handshake

A WebSocket handshake request from the browser looks something like this:

GET/HTTP/1.1 Connection: Upgrade Upgrade: websocket Host: example.com Origin: null sec-websocket-key: sN9cRrP/n9NdMgdcy2VJFQ== Sec-WebSocket-Version: 13Copy the code

One of the HTTP headers above is Upgrade. According to the HTTP1.1 protocol, the Upgrade field represents the transfer of the communication protocol from HTTP/1.1 to the protocol specified by this field. The Connection field indicates that the browser notifies the server to upgrade to the WebSocket protocol if it can. The Origin field is used to provide the domain name from which the request was issued for the server to validate (or not validate). Sec-websocket-key is the Key used for the handshake protocol and is a Base64 encoded 16-byte random string.

The server’s WebSocket responds as follows.

HTTP/1.1 101 Switching Protocols Connection: Upgrade Upgrade: websocket Sec- websocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s= Sec-WebSocket-Origin: null Sec-WebSocket-Location: ws://example.com/Copy the code

In the code above, the server also uses the Connection field to inform the browser that it needs to change the protocol. Sec-websocket-accept indicates that the server adds 258eAFa5-E914-47DA-95CA-C5AB0DC85B11 to the sec-websocket-key string provided by the browser. Then take the hash of SHA-1. The browser verifies this value to prove that the target server actually responded to the WebSocket request. The sec-websocket-location field represents the WebSocket URL to communicate with.

After the handshake is complete, the WebSocket protocol starts transmitting data on top of TCP.

The client API

Browsers handle the WebSocket protocol in three ways.

  • Establish and disconnect connections
  • Sending and receiving data
  • Handling errors

Constructor WebSocket

The WebSocket object is used as a constructor to create a new WebSocket instance.

var ws = new WebSocket('ws://localhost:8080');
Copy the code

After executing the above statement, the client will connect to the server.

webSocket.readyState

The readyState property returns the current state of the instance object, of which there are four types.

  • CONNECTING: The value is 0, indicating that a connection is being established.
  • OPEN: the value is 1, indicating that the connection is successful and communication can be started.
  • CLOSING: A value of 2 indicates that the connection is CLOSING.
  • CLOSED: the value is 3, indicating that the connection is CLOSED or fails to be opened.

Here is an example.

switch (ws.readyState) {
  case WebSocket.CONNECTING:
    // do something
    break;
  case WebSocket.OPEN:
    // do something
    break;
  case WebSocket.CLOSING:
    // do something
    break;
  case WebSocket.CLOSED:
    // do something
    break;
  default:
    // this never happens
    break;
}
Copy the code

webSocket.onopen

The onopen property of the instance object, which specifies the callback function if the connection is successful.

ws.onopen = function () { ws.send('Hello Server! '); }Copy the code

If you want to specify multiple callback functions, you can use the addEventListener method.

ws.addEventListener('open', function (event) { ws.send('Hello Server! '); });Copy the code

webSocket.onclose

The onClose property of the instance object, which specifies the callback function if the connection is closed.

ws.onclose = function(event) {
  var code = event.code;
  var reason = event.reason;
  var wasClean = event.wasClean;
  // handle close event
};

ws.addEventListener("close", function(event) {
  var code = event.code;
  var reason = event.reason;
  var wasClean = event.wasClean;
  // handle close event
});
Copy the code

webSocket.onmessage

The onMessage property of the instance object, which specifies the callback function to receive data from the server.

ws.onmessage = function(event) { var data = event.data; // process data}; ws.addEventListener("message", function(event) { var data = event.data; });Copy the code

Note that the server data can be textual 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"); }}Copy the code

In addition to dynamically determining the data type received, you can explicitly specify the binary data type received using the binaryType attribute.

Ws. binaryType = "blob"; ws.onmessage = function(e) { console.log(e.data.size); }; Ws. binaryType = "ArrayBuffer "; ws.onmessage = function(e) { console.log(e.data.byteLength); };Copy the code

webSocket.send()

The send() method of the instance object is used to send data to the server.

Example of sending text.

ws.send('your message');
Copy the code

Example of sending a Blob object.

var file = document
  .querySelector('input[type="file"]')
  .files[0];
ws.send(file);
Copy the code

An example of sending an ArrayBuffer object.

// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 300, 150);
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);
Copy the code

webSocket.bufferedAmount

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.

webSocket.onerror

The onError property of the instance object, which specifies the callback function when an error is reported.

The WebSocket server

The WebSocket protocol requires server support. Various server implementations

There are three common Node implementations.

  • uWebSockets
  • Socket.IO
  • WebSocket-Node