Introdução ao websocket (pode ser ignorado)
Websocket é um link longo de comunicação full-duplex. É usado principalmente para obter comunicação em tempo real e locais com altos requisitos de dados em tempo real. Quando o websocket não aparece, o front-end usa o treinamento de rotação setInterval para atualizar os dados. Nesses locais onde são necessários requisitos de dados em tempo real Ainda podemos usar o treinamento de rotação em áreas de baixa altitude.
(1) Com base no protocolo TCP, a implementação no lado do servidor é relativamente fácil.
(2) Possui boa compatibilidade com o protocolo HTTP. As portas padrão também são 80 e 443, e a fase de handshake usa o protocolo HTTP, portanto não é fácil bloquear durante o handshake e pode passar por vários servidores proxy HTTP.
(3) O formato de dados é relativamente leve, apresenta baixa sobrecarga de desempenho e comunicação eficiente.
(4) Você pode enviar texto ou dados binários.
(5) Não há restrição de origem e o cliente pode se comunicar com qualquer servidor.
(6) O símbolo de protocolo usual é http, enquanto websocket é ws (porta 80 padrão) e a comunicação criptografada é wss (porta padrão 443), que corresponde a https
Links HTTP longos e curtos
As conexões HTTP são divididas em conexões longas e conexões curtas, e o que comumente usamos agora é HTTP1.1, portanto, todos usamos conexões longas. Na verdade, esta frase está apenas parcialmente correta. A maioria dos nossos protocolos HTTP atuais são 1.1, então o que normalmente usamos são basicamente conexões longas. Não existem conexões longas e curtas no protocolo HTTP. O protocolo HTTP é baseado no modelo de solicitação/resposta, portanto, enquanto o servidor responder, a conexão HTTP terminará, ou mais precisamente, a solicitação HTTP terminará. Não existe conexão longa ou curta.
Links TCP longos e curtos
Conexão longa e conexão curta são, na verdade, conexões TCP. A conexão TCP é um canal bidirecional, que pode permanecer aberto por um período de tempo, portanto, a conexão TCP tem conexões realmente longas e conexões curtas. Em última análise, o protocolo HTTP é um protocolo da camada de aplicação, enquanto o TCP é o protocolo da camada de transporte real, apenas a camada responsável pela transmissão precisa estabelecer uma conexão.
Assim como o número do endereço do correio preenchido pela entrega expressa é http, e a ferramenta de transporte correspondente, como o carro, é tcp
mecanismo de pulsação websocket/mecanismo de reconexão de desconexão
Quando a comunicação entre ambas as partes estiver vinculada, se não houver motivos externos, a ligação não será interrompida se as duas partes não se desligarem.
No entanto, existem fatores externos que farão com que o websocket seja interrompido, como: (desconexão da rede, status ruim da rede, o link requer a rede interna e a rede interna não pode estar online, o processo vinculado foi encerrado/o servidor não tem comunicação por muito tempo)
Para garantir que esta comunicação permaneça ativa, precisamos adicionar um mecanismo de pulsação/mecanismo de reconexão de desconexão.
mecanismo de batimento cardíaco
Iniciar pulsação ao estabelecer conexão com o servidor (aberto)
Envie uma mensagem de pulsação ao servidor a cada 30 segundos (ou no horário especificado, 30 segundos é usado temporariamente aqui)⌛Aguarde uma resposta do servidor
Se o front-end receber uma mensagem retornada do servidor dentro dos 30 segundos especificados, ele redefinirá a pulsação e a reiniciará por 30 segundos.
Se nenhuma mensagem for recebida (pode ser por motivos de rede) e o servidor não responder, chame websocke.close() para fechar o link longo e reenviar uma nova solicitação de link para se reconectar ao servidor.
mecanismo de reconexão
Relatamos o erro /close/errno/no response no websokcet respectivamente (aqui o heartbeat chama diretamente close e depois usa close para reconectar)
Encapsular código específico
método de chamada
import { socketContact } from '@/utils/websocket'
const wss = socketContact('/ws/quality_panel/', 'quality panel data', (data) => {
tableData.value = data // 可以自定义数据处理
})
Código específico da embalagem:
const socketContact = function (contactUrl = '', getDataSecret = '', getDataFn = () => {}) {
const baseUrl = process.env.VUE_APP_API_WEBSOCKET_URL // baseURL
const callBack = getDataFn // callback返回数据函数
const url = contactUrl // 后缀url
// getDataSecret 需要发送给服务器的数据
let socket // websocket本体
let lock = false // 避免重复连接
let replyOverTime = null // 服务器回复超时setTimeout
let hearByteTime = null // 心跳 setTimeout
try {
socket = new WebSocket(baseUrl + url)
socket.addEventListener('open', function (event) {
socket.send(getDataSecret)
heatByte() // 开始心跳
console.log('链接成功', contactUrl, getDataSecret)
})
socket.addEventListener('message', function (event) {
resetHardByte() // 重置心跳
// 这里transporting...' 和'invalid command...'为服务器心跳回复 不做数据返回处理
if (event.data === 'transporting...' || event.data === 'invalid command...') return
// 处理服务器返回数据 这里可自定义
const str = event.data.replaceAll('None', 'null')
// eslint-disable-next-line no-eval
const data = eval('(' + str + ')')
callBack(data)
});
socket.addEventListener('close', function (event) {
console.log('链接关闭', event.code)
reconnect(url, getDataSecret, callBack) // 尝试重新连接
});
socket.addEventListener('errno', function (event) {
console.log('链接报错')
reconnect(url, getDataSecret, callBack)// 尝试重新连接
});
} catch (e) {
console.log('catch', e)
reconnect(url, getDataSecret, callBack) // 尝试重新连接
}
function heatByte (type) {
hearByteTime && clearInterval(hearByteTime)
replyOverTime && clearInterval(replyOverTime)
// 每30s一次心跳
hearByteTime = setTimeout(() => {
if (socket.readyState === 1) {
socket.send('heart byte') // 没问题进行心跳
console.log('heart byte')
}
// 重新链接超时 60s无回复 关闭连接 尝试重新链接
replyOverTime = setTimeout(() => {
socket.close()
console.log('网络/其他问题 回复超时间关闭')
}, 60000)
}, 30000)
}
function resetHardByte () {
// 进行下一次心跳
hearByteTime && clearTimeout(hearByteTime)
replyOverTime && clearTimeout(replyOverTime)
heatByte()
}
function reconnect (url, getDataSecret, callBack) {
if (lock) return
lock = true
setTimeout(() => {
lock = false
socketContact(url, getDataSecret, callBack)
console.log('正在尝试重新连接')
}, 5000)
}
return socket
}
export { socketContact }
referência
Link longo e link curto: http://t.csdn.cn/Ne7g3
websokcet Ruan Yifeng: https://www.ruanyifeng.com/blog/2017/05/websocket.html
websokcet: http://t.csdn.cn/j42h5