持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
websocket
一,什么是websocket
WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议)
它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的
Websocket是一个持久化的协议
二,websocket的原理
websocket约定了一个通信的规范,通过一个握手的机制,客户端和服务器之间能建立一个类似tcp的连接,从而方 便它们之间的通信
在websocket出现之前,web交互一般是基于http协议的短连接或者长连接
websocket是一种全新的协议,不属于http无状态协议,协议名为"ws"
三,websocket与http的关系
相同点:
都是基于tcp的,都是可靠性传输协议
都是应用层协议
不同点:
WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息
HTTP是单向的
WebSocket是需要浏览器和服务器握手进行建立连接的
而http是浏览器发起向服务器的连接,服务器预先并不知道这个连接
四,为什么使用websocket协议
通常情况下,客户端访问服务器端使用的是http或https协议,客户端发起请求,服务器端处理请求然后返回数据,客户端再呈现页面,
但是如果想要获取实时信息的时候,则需要通过ajax不挺的刷新数据,或者使用长连接(是对ajax的改进,客户端和服务器端建立连接后,一直保持通信,如果服务器一直没有新消息则一直保持通信,知道服务端有消息返回客户端,然后关闭连接)
不管是ajax轮询还是长连接都是:客户端主动发起请求,服务端被动接收,服务端不能主动发起;怎么才能可以由服务端主动发起将数据给客户端?那么就得使用websocket协议进行通讯。 websocket协议的优缺点
1、减少请求费时费资源
http请求需要客户端发起情况后客户端再回应,websocket服务端可以直接发起请求,减少不必要的网络请求时间损耗和网络流量
2:、更持久
http请求是无状态的,请求响应完就断开了连接,websocket经过一次握手后就一直保持连接,直到主动关闭连接
3、更主动
http服务端无法主动发起请求客户端,websocket建立连接后可以主动给客户端发消息
四、websocket协议解析
websocket协议首先需要借助http或https协议来完成握手动作,握手完成后,才会通过websocket协议进行交互
封装websocket
import { Message } from 'element-ui'
export const connectSocket = () => {
let lockReconnect = false; //避免重复连接
//判断当前浏览器是否支持WebSocket
function createWebSocket() {
try {
if ('WebSocket' in window) {
let protocol = window.location.protocol;
if (protocol === 'http:') {
window.webSocket = new WebSocket("ws://" + window.location.host + "/XXX/XXX/XXX/");
} else if (protocol === 'https:') {
window.webSocket = new WebSocket("wss://" + window.location.host + "/XXX/XXX/XXX/");
}
websocketInit()
} else {
Message.error('你的浏览器不支持websocket,请切换浏览器。');
}
} catch (e) {
websocketReconnect()
}
}
createWebSocket()
function websocketInit() {
let timeId = '';
//连接成功建立的回调方法
webSocket.onopen = function() {
console.log("webSocket连接成功");
timeId = setInterval(() => {
webSocket.send('ping');
}, 30000)
};
webSocket.onclose = function(e) {
console.log("webSocket连接关闭");
websocketReconnect()
};
//每个页面接收消息的处理方式都不同
// webSocket.onmessage = function () {
// // Notification({
// // dangerouslyUseHTMLString: true,
// // message: '<p>'+event.data+'</p>',
// // })
// // heartCheck.start();
// };
webSocket.onerror = function() {
console.log("WebSocket连接发生错误");
};
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
webSocket.close();
}
}
function websocketReconnect() {
if (lockReconnect) { // 是否已经执行重连
return;
}
lockReconnect = true;
//没连接上会一直重连,设置延迟避免请求过多
timer && clearTimeout(timer);
var timer = setTimeout(function() {
createWebSocket()
lockReconnect = false;
}, 3000);
}
};
在main.Js中挂载
import {connectSocket} from './api/api'
Vue.prototype.connectSocket = connectSocket;
页面使用
this.connectSocket()
window.webSocket.onmessage = function (event) {
console.log(event)
this.list = event.data
}
可以在页面中使用
<template>
<div></div>
</template>
<script>
export default {
data() {
return {
audio: null,
socket: null,
timeout: 30 * 1000,
heartBeatTimer: null,
reconnectTimer: null,
};
},
mounted() {
this.initWebSocket();
},
methods: {
initWebSocket() {
this.createWebSocket();
this.reconnectTimer = window.setInterval(() => {
if (this.socket.readyState === 3) {
this.stopHeartBeat();
this.createWebSocket();
}
}, 60000);
},
stopHeartBeat() {
this.heartBeatTimer = setInterval(() => {
this.socket.send("hello server!");
}, this.timeout);
},
startHeartBeat() {
clearInterval(this.heartBeatTimer);
this.heartBeatTimer = null;
},
createWebSocket() {
const host = window.location.host;
this.socket = new WebSocket(`wss://${host}/websocket`);
this.socket.onopen = this.onopen;
this.socket.onmessage = this.onmessage;
this.socket.onclose = this.onclose;
this.socket.onerror = this.onerror;
},
//用于指定连接成功后的回调函数。
onopen(event) {
this.startHeartBeat();
},
//用于指定当从服务器接受到信息时的回调函数。
onmessage(event) {
let self = this;
let message = JSON.parse(event.data);
if (message.type == "sessionId") {
//save sessionId
} else {
self.audio.play();
//做业务处理
}
},
//用于指定连接关闭后的回调函数。
onclose(event) {
console.log("成功关闭链接", event);
},
//用于指定连接失败后的回调函数。
onerror(event) {
console.log("链接出错", event);
},
},
created() {
this.audio = new Audio(require("./assets/audio/audio.mp3"));
},
beforeDestroy() {
this.socket.close();
clearInterval(this.heartBeatTimer);
clearInterval(this.reconnectTimer);
this.heartBeatTimer = null;
this.reconnectTimer = null;
},
};
</script>