為什麼需要心跳檢測?
正常的情況客戶端斷開連線會向服務端傳送一個fin包,服務端收到fin包後得知客戶端連線斷開,則立刻觸發onClose事件回撥。
心跳包格式:WebSocket協議RFC6455中有定義控制幀的格式Ping幀包含一個操作碼0x9,Pong幀包含一個操作碼0xA。客戶端傳送Ping幀,服務端收到Ping幀後回一個響應Pong幀。
但是有些極端情況如客戶端掉電、網路關閉、拔網線、路由故障等,這些極端情況客戶端無法傳送fin包給服務端,服務端便無法知道連線已經斷開。如果客戶端與服務端定時有心跳數據傳輸,則會比較及時的發現連線斷開,觸發onClose事件回撥。
另外路由節點防火牆會關閉長時間不通訊的socket連線,導致socket長連線斷開。所以需要客戶端與服務端定時傳送心跳資料保持連線不被斷開。
心跳原理
客戶端定時每X秒(推薦小於60秒)向服務端傳送特定資料(任意資料都可),服務端設定為X秒沒有收到客戶端心跳則認為客戶端掉線,並關閉連線觸發onClose回撥。這樣即透過心跳檢測請求維持了連線(避免連線因長時間不活躍而被閘道器防火牆關閉),也能讓服務端比較及時的知道客戶端是否異常掉線。
心跳包機制
WebSocket心跳包機制WebSocket心跳包是WebSocket協議的保活機制,用於維持長連線。有效的心跳包可以防止長時間不通訊時,WebSocket自動斷開連線。
心跳包是指在一定時間間隔內,WebSocket傳送的空資料包。常見的WebSocket心跳包機制如下:
客戶端
客戶端定時向伺服器傳送心跳資料包,以保持長連線。
服務端
伺服器定時向客戶端傳送心跳資料包,以檢測客戶端連線是否正常。
以上服務端會定時55秒給客戶端發心跳資料{"type":"ping"},而客戶端不需要定時向服務端傳送心跳資料。
pingNotResponseLimit = 0代表服務端允許客戶端不傳送心跳,服務端不會因為客戶端長時間沒傳送資料而斷開連線。
pingNotResponseLimit = 1,則代表客戶端必須定時傳送資料給服務端,否則pingNotResponseLimit*pingInterval=55秒內沒有任何資料發來則關閉對應連線,並觸發onClose。
說明
Gateway::$pingInterval心跳檢測時間間隔 單位:秒。如果設定為0代表不做任何心跳檢測。
Gateway:: pingNotResponseLimit次$pingInterval時間內不傳送任何資料(包括但不限於心跳資料)則斷開連結,並觸發onClose。如果設定為0代表客戶端不用傳送心跳資料,即透過TCP層面檢測連線的連通性(極端情況至少10分鐘才能檢測到連線斷開,甚至可能永遠檢測不到)
Gateway:: gateway->pingData設定為服務端要傳送的心跳請求資料,心跳資料是任意的,只要客戶端能識別即可。客戶端收到心跳資料可以忽略不做任何處理。
注意
當設定為服務端主動傳送心跳時,心跳間隔並不是100%精準。當客戶端連線成功後,服務端發來的第一個心跳的時間間隔可能要小於伺服器設定的值。
當設定為服務端主動傳送心跳時,如果客戶端最近有發來資料,那麼證明客戶端存活,服務端會省略一個心跳,下個心跳大約1.5*$gateway->pingInterval秒後傳送。
如果心跳是客戶端傳送,$gateway->pingNotResponseLimit最好大於0,這樣可以及時檢測到一些死連線(連線已經斷開,但是服務端不知道)
心跳機制原理
WebSocket心跳機制的原理是利用心跳包及時傳送和接收資料,保證WebSocket長連線不被斷開。
WebSocket心跳機制的原理可以用下面的流程來說明:
客戶端建立WebSocket連線。
客戶端向伺服器傳送心跳資料包,伺服器接收並返回一個表示接收到心跳資料包的響應。
當伺服器沒有及時接收到客戶端傳送的心跳資料包時,伺服器會發送一個關閉連線的請求。
伺服器定時向客戶端傳送心跳資料包,客戶端接收並返回一個表示接收到心跳資料包的響應。
當客戶端沒有及時接收到伺服器傳送的心跳資料包時,客戶端會重新連線WebSocket
心跳機制作用
保持WebSocket連線不被斷開。
檢測WebSocket連線狀態,及時處理異常情況。
減少WebSocket連線及伺服器資源的消耗。
完整程式碼
服務端心跳(不推薦)
修改配置檔案config\plugin\webman\gateway-worker\process.php程序配置檔案。
控制檯檢測記錄
客戶端心跳(推薦)
控制檯檢測記錄
斷線重連
不管是客戶端傳送心跳還是服務端傳送心跳,連線都有斷開的可能。例如瀏覽器最小化js被暫停、瀏覽器切換到其它tab頁面js被暫停、電腦進入睡眠等等、移動端切換網路、訊號變弱、手機黑屏、手機應用切換到後臺、路由故障、業務主動斷開等。尤其是外網環境複雜,很多路由節點會清理1分鐘內不活躍的連線,這也是為什麼心跳間隔推薦小於1分鐘的原因。
連線在外網環境很容易被斷開,所以斷線重連是長連線應用必須具備的功能(斷線重連只能客戶端做,服務端無法實現)。例如瀏覽器websocket需要監聽onclose事件,當發生onclose時建立新的連線(為避免需崩可延建立連線)。更嚴格一點,服務端也應該定時發起心跳資料,並且客戶端需要定時監測服務端的心跳資料是否超時,超過規定時間未收到服務端心跳資料應該認定連線已經斷開,需要執行close關閉連線,並重新建立新的連線。