This is the 17th day of my participation in the August Text Challenge.More challenges in August
1. Why WebSocket?
WebSocket is a protocol out of HTML5. Some people ask, we already have HTTP, why do we need another protocol? What good can it do?
The simple answer is that the HTTP protocol has a flaw: communication can only be initiated by the client. Moreover, 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. We can only use “polling” : every once in a while, we issue a query to see if the server has any new information.
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
2. Introduction to 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. 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 screen during 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, and the client can communicate with any server. (6) The protocol identifier is' WS '(or' WSS 'if encrypted), and the server URL is the URL.Copy the code
3. Advantages of webSocket
First, Websocket is a persistent protocol, as opposed to HTTP, which is not persistent. The traditional HTTP lifecycle is defined by a Request, i.e., a Request and a Response. In HTTP1.0, the HTTP Request ends.
Improvements were made in HTTP1.1 to have a keep-alive, that is, multiple requests can be sent and multiple responses received within an HTTP connection.
But remember that Request = Response, which is always the case in HTTP, means that there can only be one Response per Request. Moreover, this response is also passive and cannot be initiated actively
Websocket is based on HTTP protocol, or borrows HTTP protocol to do part of the handshake, in the handshake phase is the same
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
Copy the code
Note: this is the Websocket protocol, please use Websocket protocol processing
First, sec-websocket-key is a Base64 encode value, which the browser randomly generates to tell the server: I'm going to verify that this is really a WebSocket protocol. And then sec_websocket-protocol is a user-defined string that distinguishes the Protocol that is required for a different service from the URL. Finally, sec-websocket-version tells the server which Version of the WebSocket Protocol is used. The server then returns the following message indicating that the request was received and the Websocket was successfully established. 支那Copy the code
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
Copy the code
This is the last area of HTTP, telling the client that I have successfully switched protocols, and telling the client that the Websocket protocol is about to be upgraded. At this point, HTTP has done all its work, and it is now complete with Websocket
4, the webSocket API
(1) Create a WebSocket instance
var ws = new WebSocket('ws://localhost:8080');
Copy the code
(2) webSocket.readyState
Four WebSocket states
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.Copy the code
(3) webSocket.onopen
Specifies the callback function after a successful connection.
ws.onopen = function () { ws.send('Hello Server! '); }Copy the code
(4) webSocket.onclose
Specifies the callback function after the connection is closed
ws.onclose = function(event) { var code = event.code; var reason = event.reason; Action close event};Copy the code
(5) webSocket.onmessage
Specifies the callback function to receive server data
ws.onmessage = function(event) { var data = event.data; // process data};Copy the code
(6) webSocket.send
Used to send data to the server.
ws.send('your message');
Copy the code
(7) webSocket.onerror
Used to specify the callback function when an error is reported.
socket.onerror = function(event) {
// handle error event
};
Copy the code
5, webSocket actual combat encapsulation
const Base64 = window.Base64
let timeoutObj = null // Heartbeat countdown
let serverTimeoutObj = null // Heartbeat countdown
let reconnetNum = 0 // Reconnection times
let lockReconnect = false // Whether to re-establish the connection
let timeoutnum = null // Disconnect the reconnection countdown
let receiveNews = [] // Received message
let isOrReceive = false // Whether the message is received within 45 seconds
let webSocketUrl = ' ' // websocket creates the address
let websocket = null
var wsModuleObj = ' ' // Owning module
let wsSystem = ' ' // Owning system
let messageId = ' ' / / message ID
const sendObj = {
load: {},
path: 'internal/heart_beat'.protocolId: 'PROTO_HEART_BEAT'.sourceType: 'request'.taskId: ' '
}
/ * * *@description Heartbeat messages dynamically generate 16-bit string */
function uuid() {
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)}return (S4() + S4() + The '-' + S4() + The '-' + S4() + The '-' + S4() + The '-' + S4() + S4() + S4())
}
// Reconnect
function reconnect(wsUrls) {
addLog(JSON.stringify('The link has been broken,' + new Date().toString()), 2004)
Message({message: 'Websocket link is down'.type: 'error'})
if (lockReconnect){
return
}
lockReconnect = true
// Set delay to avoid too many requests
timeoutnum && clearTimeout(timeoutnum)
timeoutnum = setTimeout(function () {
if (reconnetNum < 4) {
reconnetNum++
websocket = null
createWebSocket(wsUrls)
lockReconnect = false
} else {
timeoutObj && clearInterval(timeoutObj)
timeoutnum && clearTimeout(timeoutnum)
websocket.close()
messageBox()
return}},20000)}// Create two timers
function heartCheck() {
// The first timer sends a message to the back end every 20 seconds
timeoutObj && clearInterval(timeoutObj)
timeoutObj = setInterval(() = > {
websocketsend(sendObj)
}, 20000)
serverTimeoutObj && clearInterval(serverTimeoutObj)
// The second timer monitors if the back end sends me a heartbeat every 45S
serverTimeoutObj = setInterval(() = > {
if(isOrReceive) {
isOrReceive = false
} else {
reconnect(webSocketUrl)
}
},45000)}// The connection succeeded
function wsOnopen() {
reconnetNum = 0
heartCheck() // Enable heartbeat monitoring
}
// An exception occurred
function wsOnerror(e) {
reconnect(webSocketUrl) // An exception occurred
}
// Close the link
export function websocketclose(e) {
websocket.close()
}
/ * * *@description Receive messages pushed by the server@param {message event parameters} e
* @param {owning module} moduleObj
* @param {Owning system} system* /
export function websocketonmessage(e, moduleObj, system) {
if (e && e.data) { // The module that sends the message
const tempData = JSON.parse(e.data)
const redata = tempData.load
if (tempData.path === 'internal/heart_beat') { // If it is a heartbeat message
isOrReceive = true // Tell the 45S timer that a heartbeat message was received
sendObj.load = redata
} else {
for (let i = 0; i < moduleObj.length; i++) {
if(tempData.path ! = ='internal/heart_beat' ) {
const logInfo = { 'messageId:': redata.msgId, 'content': redata.content, 'all': redata}
receiveNews.unshift(redata)
if(messageId ! == redata.messageId) { moduleObj[i].val(redata) messageId = redata.messageId } receiveNews = [] } } } } }/ * * *@description Send information to the server@param {message content}} msg
*/
function websocketsend(msg) {
var jsonString = JSON.stringify(msg)
if (websocket.readyState === 1) { // If the connection is normal
websocket.send(jsonString)
}
}
/ * * *@description WebSocket registration method *@param {environment variables} env
* @param {owning module} moduleObj
* @param {Owning system} system
* @param {} UM account um
* @param {token identity}} token
*/
export function register(env, moduleObj, system, um) {
addLog(JSON.stringify(Initializing long links:+ um + ', ' + system + ', ' + moduleObj + ', ' + env + ', ' +
new Date().toString()), 2002)
initWebSocket(env, moduleObj, system, um)
}
// Initializes the creation of webSocketUrl
function initWebSocket(env, moduleObj, system, umId) {
wsModuleObj = moduleObj
wsSystem = system || window.localStorage.getItem('systemId')
let wsUrls
const um = umId || window.localStorage.getItem('umId')
const base64 = new Base64(um.toUpperCase())
let token = base64.encode(um)
if (env === 'stg') {
wsUrls = 'ws://xxxxx'
} else if (env === 'prd') {
wsUrls = 'ws://xxxxx'
} else if (env === 'dev') {
wsUrls = 'ws://xxxxx'
}
wsUrls = wsUrls + '? token=' + token + '&system=' + wsSystem
webSocketUrl = wsUrls
createWebSocket(webSocketUrl)
}
/ * * *@description Create a long link and initialize the method *@param {long link address} url* /
function createWebSocket(url) {
if ('WebSocket' in window) { // Check whether the current browser supports WebSocket
if(! websocket) { websocket =new WebSocket(url) // Initialize the webSocket
init() // Initializes the webSocket method}}else {
alert('Current browser Not support websocket')}}/ * * *@description Initialize the WebSocket event */
function init() {
sendObj.taskId = uuid() // Initialize taskId
websocket.onerror = wsOnerror // Link error
websocket.onclose = websocketclose // Link closed
websocket.onopen = wsOnopen // The link succeeded
websocket.onmessage = (e) = > { websocketonmessage(e, wsModuleObj, wsSystem) } // Receive information
}
Copy the code