一、websocket
websocket是什么?为什么要用websocket?
websocket是一种网络通信呢协议,同http、https协议,是客户端与服务端通信用的,websocket创建在 TCP 上、通过HTTP/1.1 协议的101状态码进行握手。
为什么要用websocket?试想以下场景:
你妈妈在厨房做饭,你饿得不行,想马上吃到,但是妈妈不着急,她做完饭可能刷个锅洗个碗,你想在第一时间吃到饭,就得知道饭做好的消息,排油烟机声音太大得开门才能听到。
用http连接:
你(进厨房):妈妈饭好了吗?
妈妈:没好呢,再等会儿吧。
你(5分钟后又进厨房):妈妈饭好了吗?
妈妈(🙄️):急什么急,你急你做!
你(又5分钟又进厨房):妈妈饭好了吗……
妈妈:好了好了好了,催催催,饿死鬼!
用websocket连接:
你在卧室愉快玩手机(和妈妈约定饭做好后主动告诉你)
妈妈(第一时间):饭好了,出来端吧。
你:好嘞,来啦!
妈妈是服务端,你是客户端,想要服务端有新消息主动发给客户端,就要使用1、http连接,setInterval轮询请求接口获取消息或2、websocket连接,服务端主动发送消息。
二、使用websocket
这里使用了websocket结合vue的一个插件vue-native-websocket
,地址:https://github.com/nathantsoi/vue-native-websocket,优点可以自动重连,缺点是找不到暴露的重连api reconnect,也可能我笨没找到😭
main.js中引用
import websocket from 'vue-native-websocket';
Vue.use(websocket, '', {
connectManually: true, // 手动连接
format: 'json', // json格式
reconnection: true, // 是否自动重连
reconnectionAttempts: 5, // 自动重连次数
reconnectionDelay: 2000, // 重连间隔时间
});
index.vue
data() {
return {
paramA: "aa",
paramB: 123,
food: "",
drink: "",
num: 2, // 两碗饭
}
},
mounted() {
this.initWebSocket();
},
sockets: {
// 连接成功
onopen() {
console.log("socket success");
},
// 接收消息
onmessage(e) {
console.log("===data", JSON.parse(e.data));
// 服务端传过来的值
let { event, data } = JSON.parse(e.data);
// 妈妈:饭好了事件
if(event === "FOOD_DONE") {
this.getFood(data);
};
},
// 连接报错
onerror() {},
// 关闭连接
onclose() {
console.log("socket close");
},
},
destroyed() {
// 销毁websocket
this.$disconnect();
},
methods: {
initWebSocket({
this.$connect(`//${location.host}/game/api/websocket/food/${this.paramA}/1/${this.paramB}`);
},
getFood(data) {
this.food = data.food || "";
this.drink = data.drink || "";
},
// 吃饭事件,把吃了几碗饭告诉妈妈
// ws中ws.send实现,注意JSON.stringify转下格式或其他服务端要的格式
haveFood() {
this.$socket.sendObj({
event: "HAVE_FOOD",
data: this.num
});
}
},
三、心跳
还是妈妈在做饭,你在卧室玩手机,妈妈做饭做着做着去洗衣服了(妈妈:???),你饿得不行,还在等妈妈喊你吃饭,但是过了好久也没收到消息,这种情况我们就需要提前约定好,你们需要定期沟通:
你:妈妈还在厨房吗1?
妈妈:在呢1。
你(收到1固定时间后):妈妈还在厨房吗2?
妈妈:在呢2。
……
这种连接机制叫心跳,服务端和客户端互相发消息确认连接状态。如果网络断开了,服务端并没有发送onclose信息,客户端就会一直等待,此时就需要心跳机制,确认websocket连接状态,保证websocket的良好连接。
index.vue
心脏跳动pingping pongpong❤️
data() {
return {
ping: 0,
pong: 0,
pingTimer: null,
}
},
sockets: {
// 连接成功
onopen() {
console.log("socket success");
// 每30s向服务端发ping+1参数,服务端返回pong参数+1,再对比确认连接状态
this.pingTimer = setInterval(() => {
if(this.ping === this.pong) {
this.ping += 1;
this.$socket.sendObj({
event: "PING",
data: this.ping
});
} else {
this.reconnectPing();
}
}, 30000)
},
// 接收消息
onmessage(e) {
console.log("===data", JSON.parse(e.data));
// 服务端传过来的值
let { event, data } = JSON.parse(e.data);
// 妈妈:饭好了事件;心跳:在做饭呢
if(event === "FOOD_DONE") {
this.getFood(data);
};
if(event === "PONG") {
this.onPong(data);
}
},
// 关闭连接
onclose() {
console.log("socket close");
clearInterval(this.pingTimer);
this.pingTimer = null;
},
},
methods: {
onPong(data) {
this.pong = data;
},
reconnectPing() {
// 这个插件没找到this.$socket.reconnect方法呢,项目中判断次数后返回首页了,建议重连
}
},
四、websocket优缺点
优点:
相对于http/https效率高,自动更新服务端数据无需页面刷新,耗费资源少,速度快。
缺点:
多条数据传输都依赖一条websocket连接,要保证连接的稳定性、错误处理、心跳机制的稳定性;对前后端尤其是后端开发同学要求更高,需要理清发送消息的时间,发送的事件及数据,也要保证ws的稳定性。