websocket解析

什么是websocket

  1. WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议)
  2. 它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的
  3. Websocket是一个持久化的协议

websocket的原理

  1. websocket约定了一个通信的规范,通过一个握手的机制,客户端和服务器之间能建立一个类似tcp的连接,从而方便它们之间的通信
  2. 在websocket出现之前,web交互一般是基于http协议的短连接或者长连接
  3. websocket是一种全新的协议,不属于http无状态协议,协议名为”ws”

websocket与http的关系

相同点:

  1. 都是基于tcp的,都是可靠性传输协议
  2. 都是应用层协议

不同点:

  1. WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息
  2. HTTP是单向的
  3. WebSocket是需要浏览器和服务器握手进行建立连接的
  4. http是浏览器发起向服务器的连接,服务器预先并不知道这个连接

联系

WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的

总结

  1. 首先,客户端发起http请求,经过3次握手后,建立起TCP连接;http请求里存放WebSocket支持的版本号等信息,如:Upgrade、Connection、WebSocket-Version等;
  2. 然后,服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据;
  3. 最后,客户端收到连接成功的消息后,开始借助于TCP传输信道进行全双工通信。

JS websocket实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import Store from "@/store";
class WebSocketClass {
// 要连接的URL
url;
// 一个协议字符串或一个协议字符串数组。
// 这些字符串用来指定子协议,这样一个服务器就可以实现多个WebSocket子协议
protocols;
// WebSocket 实例
ws;
// 是否在重连中
isReconnectionLoading = false;
// 延时重连的 id
timeId = null;
// 是否是用户手动关闭连接
isCustomClose = false;
// 错误消息队列
errorStack = [];

constructor(url, protocols) {
this.url = url;
this.protocols = protocols;
this.createWs();
}

createWs() {
if ("WebSocket" in window) {
// 实例化
this.ws = new WebSocket(this.url, this.protocols);
// 监听事件
this.onopen();
this.onerror();
this.onclose();
this.onmessage();
} else {
console.log("你的浏览器不支持 WebSocket");
}
}

// 监听成功
onopen() {
this.ws.onopen = () => {
console.log("onopen");
// 发送成功连接之前所发送失败的消息
this.errorStack.forEach((message) => {
this.send(message);
});
this.errorStack = [];
this.isReconnectionLoading = false;
};
}

// 监听错误
onerror() {
this.ws.onerror = (err) => {
console.log(err, "onerror");
this.reconnection();
this.isReconnectionLoading = false;
};
}

// 监听关闭
onclose() {
this.ws.onclose = () => {
console.log("onclose");

// 用户手动关闭的不重连
if (this.isCustomClose) return;

this.reconnection();
this.isReconnectionLoading = false;
};
}

// 接收 WebSocket 消息
onmessage() {
this.ws.onmessage = (event) => {
try {
Store.dispatch("user/setData", event.data);
} catch (error) {
console.log(error, "error");
}
};
}

// 是否连接中
isConnection() {
if (this.ws && this.ws.readyState === WebSocket.OPEN) return true
else return false
}

// 重连
reconnection() {
// 防止重复
if (this.isReconnectionLoading) return;

this.isReconnectionLoading = true;
clearTimeout(this.timeId);
this.timeId = setTimeout(() => {
this.createWs();
}, 100);
}

// 发送消息
send(message) {
// 连接失败时的处理
if (this.ws.readyState !== 1) {
this.errorStack.push(message);
return;
}

this.ws.send(message);
}

// 手动关闭
close() {
this.isCustomClose = true;
this.ws.close();
}

// 手动开启
start() {
this.isCustomClose = false;
this.reconnection();
}

// 销毁
destroy() {
this.close();
this.ws = null;
this.errorStack = null;
}
}

export default WebSocketClass;