Original is not easy, I hope you can pay attention to us, and then easily point a praise ~~
This article was first published in the blog of the front-end team of the political cloud: WebSocket principle analysis and implementation of a simple chat
preface
With the development of the Web, users for the Web real-time push requirements are increasingly high, before the emergence of WebSocket, in most cases is through the client to initiate polling to get real-time updates of the server data, because http1. x protocol has a defect is that communication can only be initiated by the client. The server cannot actively push to the client. This method is obviously inefficient and has poor experience in scenarios with high requirements on real-time performance, such as instant messaging and instant quotation. In order to solve this problem, the WebSocket protocol came into being, which realized the capability of two-way communication between the client and the server. Before introducing WebSocket, let’s look at the way polling implements push.
Short Polling (Polling)
The idea behind short polling is that the browser sends an HTTP request to the server every few seconds, and the server responds directly to the request, regardless of whether there is any data update. When the server response is complete, the TCP connection will be closed. The simplest code implementation is to use XHR to send a request to the back end by setInterval to get the latest data.
setInterval(function() {
fetch(url).then((res) = > {
// success code})},3000);
Copy the code
- Advantages: Simple implementation.
- Disadvantages: May cause data in a short period of time out of sync and a large number of invalid requests, poor security, waste resources.
Long Polling (long-polling)
After the client sends a request, the server will not immediately return data. The server will block the request and the connection will not be disconnected immediately. The connection will not be returned until the server has data update or the connection times out. The general effect is as follows:
The client code is as follows:
function async() {
fetch(url).then((res) = > {
async(a);// success code
}).catch((a)= > {
/ / timeout
async();
})
}
Copy the code
- Advantages: Polling has been optimized, with better timeliness.
- Disadvantages: Keeping the connection pending consumes resources, the server does not return valid data, and the program times out.
WebSocket
The short Polling (Polling) and Long Polling (Polling) mentioned above both require the client to initiate Ajax requests before they can communicate, using the HTTP protocol, so the server cannot actively push information to the client.
When there are scenarios like sporting events, chat rooms, real-time locations, and so on, polling is inefficient and a waste of resources because you’re constantly sending requests to connect to the server. WebSocket, so that the server can take the initiative to send information to the client, so that the browser has real-time two-way communication ability.
For those of you who haven’t used WebSocket, you might think it’s some kind of advanced technology. In fact, the WebSocket API is not very common and easy to learn, but before introducing how to use it, let’s take a look at its communication principle.
Communication principle
When the client wants to establish a WebSocket connection with the server, during the handshake between the client and the server, the client will first send an HTTP request to the server, including an Upgrade request header to inform the server that the client wants to establish a WebSocket connection.
Setting up a WebSocket connection on the client side is very simple:
let ws = new WebSocket('ws://localhost:9000');
Copy the code
Similar to HTTP and HTTPS, WSS corresponds to WS to establish secure connections. For example, local WS. The request header looks like this:
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh; Q = 0.9Cache-Control: no-cache
Connection: Upgrade // Indicates that the connection needs to Upgrade the protocolCookie: _hjMinimizedPolls=358479; ts_uid=7852621249; CNZZDATA1259303436=1218855313-1548914234-%7C1564625892; csrfToken=DPb4RhmGQfPCZnYzUCCOOade; JSESSIONID=67376239124B4355F75F1FC87C059F8D; _hjid=3f7157b6-1aa0-4d5c-ab9a-45eab1e6941e; acw_tc=76b20ff415689655672128006e178b964c640d5a7952f7cb3c18ddf0064264
Host: localhost:9000
Origin: http://localhost:9000
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: 5fTJ1LTuh3RKjSJxydyifQ== // Corresponds to the response header sec-websocket-AcceptSec-WebSocket-Version: 13 // Indicates the webSocket protocol versionUpgrade: websocket // Indicates the webSocket protocol to be upgradedUser-Agent: Mozilla / 5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36Copy the code
The response header is as follows:
Connection: Upgrade
Sec-WebSocket-Accept: ZUip34t+bCjhkvxxwhmdEOyx9hE=
Upgrade: websocket
Copy the code
In the response line (General), you can see that the status code is 101 Switching Protocols, indicating that the connection has been converted from HTTP to WebSocket communication protocol. After a successful conversion, the connection is not broken, but a full-duplex communication is established, and subsequent messages are sent and received over this connection channel.
Note that there is an SEC-websocket-key field in the request header that matches the sec-websocket-Accept field in the corresponding header to provide basic protection against malicious or invalid connections. Sec-websocket-key is a base64 encoding randomly generated by the client. The server uses this encoding according to a fixed algorithm:
GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // A fixed string accept = base64(sha1(key + GUID)); // key is sec-websocket-key, accept is sec-websocket-acceptCopy the code
The GUID string is a fixed string officially defined by RFC6455 and cannot be modified.
After receiving the sec-websocket-accept response from the server, the client calculates the sec-websocket-key generated by the client using the same algorithm. If a match is found, the handshake succeeds. Then determine whether the HTTP Response status code is 101 (switching protocol). If so, establish a connection and you are done.
Simple single chat
Below to achieve a pure text message type of one to one chat (single chat) function, nonsense not to say, directly on the code, pay attention to see comments.
Client:
function connectWebsocket() {
ws = new WebSocket('ws://localhost:9000');
// The listening connection succeeded
ws.onopen = (a)= > {
console.log('Server WebSocket connection successful');
ws.send(JSON.stringify(msgData)); The send method sends a message to the server
};
// Listen for server messages (receive messages)
ws.onmessage = (msg) = > {
let message = JSON.parse(msg.data);
console.log('Message received:', message)
elUl.innerHTML += '<li class="b">${message.content}</li>`;
};
// Listening connection failed
ws.onerror = (a)= > {
console.log('Connection failed, reconnecting... ');
connectWebsocket();
};
// The listening connection is closed
ws.onclose = (a)= > {
console.log('Connection closed');
};
};
connectWebsocket();
Copy the code
As you can see above, the WebSocket instance API is easy to understand and simple to use. The send() method is used to send messages, and the onMessage event is used to receive messages, which are then processed and displayed on the page. When the onError event (listening for connection failure) is raised, it is best to perform reconnection to keep the connection alive.
Server Node: (here using the WS library)
const path = require('path');
const express = require('express');
const app = express();
const server = require('http').Server(app);
const WebSocket = require('ws');
const wss = new WebSocket.Server({ server: server });
wss.on('connection', (ws) => {
// Listen for messages from clients
ws.on('message', (message) => {
console.log(wss.clients.size);
let msgData = JSON.parse(message);
if (msgData.type === 'open') {
// Identify the session during the initial connection
ws.sessionId = `${msgData.fromUserId}-${msgData.toUserId}`;
} else {
let sessionId = `${msgData.toUserId}-${msgData.fromUserId}`;
wss.clients.forEach(client= > {
if (client.sessionId === sessionId) {
client.send(message); // Send a message to the corresponding client connection}})}})// The connection is closed
ws.on('close', () = > {console.log('Connection closed');
});
});
Copy the code
Similarly, the server also has corresponding methods of sending and receiving. See the full sample code here
The browser and server can then happily send messages as follows:
The green arrow indicates the sent message, and the red arrow indicates the received message.
Heart keep alive
In the actual use of WebSocket, there may be some unstable connection when there is no message for a long time. The connection interruption caused by these unknown conditions will affect the previous communication between the client and the server.
To prevent this, there is a way to keep the heartbeat alive: the client sends a ping at regular intervals, like a heartbeat, to tell the server that I’m still alive, and the server returns Pong to tell the client that the server is still alive. Ping/Pong is actually a non-business related fake message, also known as a heartbeat packet.
After the connection is successful, heartbeat packets can be sent at fixed intervals, such as 60s:
setInterval((a)= > {
ws.send('This is a heartbeat packet message.');
}, 60000)
Copy the code
conclusion
Through the above introduction, we should have a certain understanding of WebSocket, in fact, not mysterious, here is a simple summary of the article content. When a WebSocket instance is created, an HTTP request is sent with a special field “Upgrade” in the request packet. Then the connection is converted from HTTP to WebSocket. In this way, the client and server establish full-duplex communication. Information can be exchanged over this communication connection through the WebSocket send method and the onMessage event.
, recruiting
ZooTeam, a young passionate and creative front-end team, belongs to the PRODUCT R&D department of ZooTeam, based in picturesque Hangzhou. The team now has more than 50 front-end partners, with an average age of 27, and nearly 30% of them are full-stack engineers, no problem in the youth storm group. The members consist of “old” soldiers from Alibaba and NetEase, as well as fresh graduates from Zhejiang University, University of Science and Technology of China, Hangzhou Electric And other universities. In addition to daily business docking, the team also carried out technical exploration and practice in material system, engineering platform, building platform, performance experience, cloud application, data analysis and visualization, promoted and implemented a series of internal technical products, and continued to explore the new boundary of front-end technology system.
If you want to change what’s been bothering you, you want to start bothering you. If you want to change, you’ve been told you need more ideas, but you don’t have a solution. If you want change, you have the power to make it happen, but you don’t need it. If you want to change what you want to accomplish, you need a team to support you, but you don’t have the position to lead people. If you want to change the pace, it will be “5 years and 3 years of experience”; If you want to change the original savvy is good, but there is always a layer of fuzzy window… If you believe in the power of believing, believing that ordinary people can achieve extraordinary things, believing that you can meet a better version of yourself. If you want to be a part of the process of growing a front end team with deep business understanding, sound technology systems, technology value creation, and impact spillover as your business takes off, I think we should talk. Any time, waiting for you to write something and send it to [email protected]
Recommended reading
1024 great offering!! A review of the best of the past year
Probably the most complete collection of text overflow truncation ellipsis schemes
Move the universe! React can also “use” computed properties