WebSocketハートビートメカニズムとコード
9599 ワード
本文は主にwebsocket心拍数を設計する場合にどのような問題を考慮する必要があるかを述べる.
前言
Websocketを使用すると、クライアントネットワークが閉じている場合がありますが、サービス側でoncloseイベントがトリガーされません.次のようになります.余分な接続 サービス側はクライアントにデータを送信し続け、これらのデータは を失う.
したがって、クライアントとサービス側が正常に接続されているかどうかを検出するメカニズムが必要です.これがwebsocketのドキドキです.この名前はとても生き生きしていて、ドキドキ説明がまだ生きていて(正常な接続を維持しています)、ドキドキ説明がなくて(接続が切れています).
解決すべき問題
私のコードは主に以下のいくつかの問題を解決しました.接続後、毎秒1つの心拍が送信され、サーバは同じように1つの心拍を返し、サーバが停止していないことを示します. 断線再接続(私たちがテストした環境はネットワーク接続を切断している)では、ネットワークを切断した後、ハートビートパケットが送信できないため、現在の時間が前回成功したハートビートから20秒を超えると、接続に問題が発生したことを示し、接続を閉じる必要があります. 最初に接続を閉じるとwebsocketが再接続を試み、10秒の期間が設定されます.10秒以内に(ネットワーク接続を復元)接続できればメッセージの送受信を継続でき、接続できなければ閉鎖され、再接続されません. 30秒以内にサーバメッセージ(心拍数毎秒送信)が受信されず、サーバが停止していると思ったらcloseイベントを呼び出し、3ステップ目に進みます.
必要なもの
考えが行き届かず、命名が規範化されていない.タイマー 前回心拍数が成功した時間 が接続を切断した場合( が 接続が切断された場合( は、サーバが30秒以内にメッセージを返したかどうかを示す30秒のsettimeoutタイマ
コードセクション
私はreactでwebsocketを使ってドキドキしました.ユーザーがログインするとwebsocket接続を確立します.reduxが使用されているため、この部分のコードは
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
前言
Websocketを使用すると、クライアントネットワークが閉じている場合がありますが、サービス側でoncloseイベントがトリガーされません.次のようになります.
したがって、クライアントとサービス側が正常に接続されているかどうかを検出するメカニズムが必要です.これがwebsocketのドキドキです.この名前はとても生き生きしていて、ドキドキ説明がまだ生きていて(正常な接続を維持しています)、ドキドキ説明がなくて(接続が切れています).
解決すべき問題
私のコードは主に以下のいくつかの問題を解決しました.
必要なもの
考えが行き届かず、命名が規範化されていない.
ws.keepAliveTimer
は、心拍数を毎秒1回送信するために使用される.ws.last_health_time
および現在の時間let time = new Date().getTime();
.ws.close()
)、closeイベントが発生した後に10秒再接続する必要があるため、reconnect
時間がかかります.reconnectMark
に再接続されているかどうか.ws.close()
)、wsオブジェクトtempWs
を保存する必要があります.ws = { ...ws }
でバインドが失われるイベントを発見しようとしたことがあります.ws.receiveMessageTimer
である.コードセクション
私はreactでwebsocketを使ってドキドキしました.ユーザーがログインするとwebsocket接続を確立します.reduxが使用されているため、この部分のコードは
componentWillReceiveProps
に置かれている.componentWillReceiveProps(nextProps) {
if(nextProps.isLogin && !this.state.notificationSocket) { // websocket
let ws = new WebSocket(`${chatUrl}/${nextProps.userId}`);
ws.last_health_time = -1; //
ws.keepalive = function() {
let time = new Date().getTime();
if(ws.last_health_time !== -1 && time - ws.last_health_time > 20000) { // 20s
ws.close()
} else {
// ,ws.send 。ws.bufferedAmount 0。
if(ws.bufferedAmount === 0 && ws.readyState === 1) {
ws.send('h&b');
ws.last_health_time = time;
}
}
}
if(ws) {
let reconnect = 0; //
let reconnectMark = false; //
this.setState({
notificationSocket: true
})
ws.onopen = () => {
reconnect = 0;
reconnectMark = false;
ws.receiveMessageTimer = setTimeout(() => {
ws.close();
}, 30000); // 30s , , 。 , 。
if(ws.readyState === 1) { // 1 open
ws.keepAliveTimer = setInterval(() => {
ws.keepalive();
}, 1000)
}
}
ws.onerror = () => {
console.error('onerror')
}
ws.onmessage = (msg) => {
/* ,
msg = JSON.parse(msg.data);
let chatObj = JSON.parse(localStorage.getItem(CHATOBJECT)) || {};
if(msg && msg.senderUserId && !chatObj[msg.senderUserId]) chatObj[msg.senderUserId] = [];
if(msg.content !== 'h&b') {
if(msg.chat === true) { //
// chatObj[msg.senderUserId] = [new Date().getTime()}>{msg.content}
, ...chatObj[msg.senderUserId]]
chatObj[msg.senderUserId].unshift(msg.content);
WindowNotificationUtils.notice(msg.title, msg.content, () => {
const { history } = this.props;
history.replace({
pathname: '/sendNotice',
search: `?senderUserId=${msg.senderUserId}` // url,
});
})
localStorage.setItem(CHATOBJECT, JSON.stringify(chatObj));
this.props.dispatch({
type: UPDATE_CHAT
})
} else { //
WindowNotificationUtils.notice(msg.title, msg.content);
}
}
*/
// ,
clearTimeout(ws.receiveMessageTimer);
ws.receiveMessageTimer = setTimeout(() => {
ws.close();
}, 30000); // 30s , , 。
}
ws.onclose = () => {
clearTimeout(ws.receiveMessageTimer);
clearInterval(ws.keepAliveTimer);
if(!reconnectMark) { // , 。
reconnect = new Date().getTime();
reconnectMark = true;
}
let tempWs = ws; // ws
if(new Date().getTime() - reconnect >= 10000) { // 10 ,
ws.close();
} else {
ws = new WebSocket(`${chatUrl}/${nextProps.userId}`);
ws.onopen = tempWs.onopen;
ws.onmessage = tempWs.onmessage;
ws.onerror = tempWs.onerror;
ws.onclose = tempWs.onclose;
ws.keepalive = tempWs.keepalive;
ws.last_health_time = -1;
}
}
}
}
}
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