正常的情況客戶端斷開連接會向服務端發送一個fin包,服務端收到fin包后得知客戶端連接斷開,則立刻觸發onClose事件回調。
心跳包格式:WebSocket協議RFC6455中有定義控制幀的格式Ping幀包含一個操作碼0x9,Pong幀包含一個操作碼0xA??蛻舳税l送Ping幀,服務端收到Ping幀后回一個響應Pong幀。
但是有些極端情況如客戶端掉電、網絡關閉、拔網線、路由故障等,這些極端情況客戶端無法發送fin包給服務端,服務端便無法知道連接已經斷開。如果客戶端與服務端定時有心跳數據傳輸,則會比較及時的發現連接斷開,觸發onClose事件回調。
另外路由節點防火墻會關閉長時間不通訊的socket連接,導致socket長連接斷開。所以需要客戶端與服務端定時發送心跳數據保持連接不被斷開。
客戶端定時每X秒(推薦小于60秒)向服務端發送特定數據(任意數據都可),服務端設定為X秒沒有收到客戶端心跳則認為客戶端掉線,并關閉連接觸發onClose回調。這樣即通過心跳檢測請求維持了連接(避免連接因長時間不活躍而被網關防火墻關閉),也能讓服務端比較及時的知道客戶端是否異常掉線。
WebSocket心跳包機制WebSocket心跳包是WebSocket協議的?;顧C制,用于維持長連接。有效的心跳包可以防止長時間不通訊時,WebSocket自動斷開連接。
心跳包是指在一定時間間隔內,WebSocket發送的空數據包。常見的WebSocket心跳包機制如下:
客戶端定時向服務器發送心跳數據包,以保持長連接。
this.heartbeatTimer = setInterval(() => { ws.send('{"event":"ping","content":"ping heartbeat"}');}, originData.ping_interval)
服務器定時向客戶端發送心跳數據包,以檢測客戶端連接是否正常。
$gateway = new Gateway("websocket://0.0.0.0:8783");$gateway->pingInterval = 55;$gateway->pingNotResponseLimit = 0;// 服務端定時向客戶端發送的數據$gateway->pingData = '{"type":"ping"}';
以上服務端會定時55秒給客戶端發心跳數據{"type":"ping"},而客戶端不需要定時向服務端發送心跳數據。
說明
當設置為服務端主動發送心跳時,心跳間隔并不是100%精準。當客戶端連接成功后,服務端發來的第一個心跳的時間間隔可能要小于服務器設置的值。
當設置為服務端主動發送心跳時,如果客戶端最近有發來數據,那么證明客戶端存活,服務端會省略一個心跳,下個心跳大約1.5*$gateway->pingInterval秒后發送。
如果心跳是客戶端發送,$gateway->pingNotResponseLimit最好大于0,這樣可以及時檢測到一些死連接(連接已經斷開,但是服務端不知道)
WebSocket心跳機制的原理是利用心跳包及時發送和接收數據,保證WebSocket長連接不被斷開。
WebSocket心跳機制的原理可以用下面的流程來說明:
修改配置文件config/plugin/webman/gateway-worker/process.php進程配置文件。
'pingInterval' => 30,'pingNotResponseLimit' => 0,'pingData' => '{"event":"ping","msg":"我是服務端主動心跳檢測"}',
控制臺檢測記錄
圖片
let $timeout = null;let ws = new WebSocket("ws://127.0.0.1:8783");ws.onopen = function(evt) { let $_content = { "event": "join", "mode": 1, "group_id": 0, "from_user_id": "10086", "from_username": "開源技術小棧", "to_user_id": "10000", "content": "加入會話", }; ws.send(JSON.stringify($_content));};ws.onmessage = function(evt) { console.log( "【開源技術小?!拷邮芟? " + evt.data); let _obj = JSON.parse(evt.data); if (_obj.data.event === 'init') { sendHeartbeat(); }};function sendHeartbeat() { console.log('客戶端定時發送心跳'); ws.send('{"event":"ping","content":"開源技術小棧我在線呢!"}'); $timeout = setTimeout(sendHeartbeat, 3000);}ws.onclose = function() { clearTimeout($timeout); console.log('沒有網了,睡覺去了');};
圖片
不管是客戶端發送心跳還是服務端發送心跳,連接都有斷開的可能。例如瀏覽器最小化js被暫停、瀏覽器切換到其它tab頁面js被暫停、電腦進入睡眠等等、移動端切換網絡、信號變弱、手機黑屏、手機應用切換到后臺、路由故障、業務主動斷開等。尤其是外網環境復雜,很多路由節點會清理1分鐘內不活躍的連接,這也是為什么心跳間隔推薦小于1分鐘的原因。
連接在外網環境很容易被斷開,所以斷線重連是長連接應用必須具備的功能(斷線重連只能客戶端做,服務端無法實現)。例如瀏覽器websocket需要監聽onclose事件,當發生onclose時建立新的連接(為避免需崩可延建立連接)。更嚴格一點,服務端也應該定時發起心跳數據,并且客戶端需要定時監測服務端的心跳數據是否超時,超過規定時間未收到服務端心跳數據應該認定連接已經斷開,需要執行close關閉連接,并重新建立新的連接。
本文鏈接:http://www.www897cc.com/showinfo-26-41704-0.htmlWebSocket:心跳檢測與重連機制,你會嗎?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com