一. 重連機制
1. 說明
默認是沒有重連機制的,需要加上withAutomaticReconnect開啟重連,默認重連4次,分別時間間隔為:0、2、10和30秒 (指掉線的瞬間馬上重連、再過2s重連、再過10s重連,再過20s重連,這里指的是間隔,而不是疊加)。當然也可以自行配置,eg:.withAutomaticReconnect([10000, 4000, 10000, 10000])。
PS: 經過測試,這里有一個現象,比如 先斷網,觸發掉線機制,然后恢復網,走重連機制,恢復后的重連的第一次是連不上的,必須第二次才能連上。第一次報錯:'Error: WebSocket closed with status code: 1006 ().
代碼分享
//安卓手機的寫法 var connection = new signalR.HubConnectionBuilder().withUrl("http://xx.xx.xx.126:8088/chathub") .withAutomaticReconnect([10000, 4000, 10000, 10000]) .build(); //蘋果的手機的寫法 (需要跳過協商) var connection = new signalR.HubConnectionBuilder().withUrl("http://xx.xx.xx.126:8088/chathub", { skipNegotiation: true, //針對webSocket為默認協議的時候,可以跳過協商 transport: signalR.HttpTransportType.WebSockets }) .withAutomaticReconnect([3000, 4000, 10000, 10000]) .build();
我們發現上述代碼,安卓和IOS寫法不一樣,這里是因為IOS系統僅支持WebSocket協議,所以要手動指定,並且跳過協商。
2. 重連的回調
(1). onreconnecting:重連之前調用 (只有在掉線的一瞬間,只進入一次),狀態為:Reconnecting 。
(2). onreconnected:(默認4次重連),任何一次只要回調成功,調用,狀態為:Connected 。
(3). onclose:(默認4次重連) 全部都失敗后,調用,狀態為:Disconnected。
3. 實戰測試
分析下面代碼,建立連接后,手機斷網,輸出1,進入了 onreconnecting 回調;大約過 3s 后,連接上網,即已經過了第一次重連的時間,進入第2個 4s的重連,過了4s,走重連機制,這個時候屬於恢復網絡后的第一次,是重連不上的,需要到了第三個重連機制,再過10s后,重連成功。
如果一直斷網,4次重連全部失敗,則會進入onclose回調。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <title></title> <script src="js/jquery.js" type="text/javascript" charset="utf-8"></script> <script src="js/signalr.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> $(function() { //蘋果的手機的寫法 (需要跳過協商) var connection = new signalR.HubConnectionBuilder().withUrl("http://XXX:8088/chathub", { skipNegotiation: true, //針對webSocket為默認協議的時候,可以跳過協商 transport: signalR.HttpTransportType.WebSockets }) .withAutomaticReconnect([3000, 4000, 10000, 10000]) .build(); //建立連接 $('#j_btn1').click(function() { connection.start().then(function() { console.log("連接成功"); $('#j_hb').append('<div>連接成功</div>') }).catch(function(err) { $('#j_hb').append('<div>' + err.toString() + '</div>') return console.error(err.toString()); }); }); //發送消息 $("#j_send").click(function() { connection.invoke("SendMessage", $("#j_content").val()).catch(function(err) { $('#j_hb').append('<div>' + err.toString() + '</div>'); return console.error(err.toString()); }); }); //接收消息 connection.on("ReceiveMessage", function(msg) { console.log(msg); $('#j_hb').append('<div>' + msg + '</div>') }); //下面測試斷線重連機制 , //重連之前調用 (只有在掉線的一瞬間,只進入一次) connection.onreconnecting((error) => { console.log(1); $('#j_hb').append('<div>1</div>'); console.log(connection.state); console.log(connection.state === signalR.HubConnectionState.Reconnecting); }); //(默認4次重連),任何一次只要回調成功,調用 connection.onreconnected((connectionId) => { console.log(2); $('#j_hb').append('<div>2</div>'); console.log(connection.state); console.log(connection.state === signalR.HubConnectionState.Connected); }); //(默認4次重連) 全部都失敗后,調用 connection.onclose((error) => { console.log('3'); $('#j_hb').append('<div>3</div>'); console.log(connection.state); console.assert(connection.state === signalR.HubConnectionState.Disconnected); }); }); </script> </head> <body> <br /> <br /> <br /> <br /> <br /> <input type="text" id="j_content" value="" /> <button id="j_btn1">建立連接</button> <button id="j_send">發送消息</button> <br /> <br /> <br /> <br /> <br /> <div id="j_hb"> </div> </body> </html>
二. 心跳監測機制
1. 何為心跳監測機制
當客戶端和app端不發送消息的時候,這個時候需要一種機制,來相互ping,保證客戶端和服務器端是連接狀態的,從而一直保證在線狀態哦。這里有兩套機制來保證,分別是告訴客戶端,服務器是正常的;告訴服務器端,客戶端是在線的。SignalR提供了兩套監測機制,來保證長久連接在線不掉,或者刪掉不必要的客戶端,釋放資源。
2. 配置說明
(1). 服務端配置
A. clientTimeoutInterval:表示客戶端如果在30s內沒有向服務器發送任何消息,那么服務器端則會認為客戶端已經斷開連接了,則進入OnDisconnectedAsync方法, 但實際上 客戶端此時可能並沒有斷開連接,或者斷開連接還需要一段時間,因為客戶端斷開連接是走的另外一套機制的。【以服務器端為基准,判斷客戶端是否斷開連接,從而斷開服務器端連接】
B. keepAliveinterval: 表示如果服務器未在15s內向客戶端發送消息,在15s的時候服務器會自動ping客戶端,是連接保持打開的狀態。【用於控制服務端自動ping客戶端的時間】
(2). 客戶端配置
A. serverTimeoutInMilliseconds:表示客戶端如果在30s內收到服務器端發送的消息,客戶端會斷開連接,進入onclose事件。(前提是沒有啟動:自動重連機制,已測試)。 它和服務器端的keepAliveinterval是一對的,該值必須比服務器端的serverTimeoutInMilliseconds值大,建議是它的兩倍。【是以客戶端為基准,判斷服務器端是否斷開連接,從而斷開客戶端連接】
B. keepAliveIntervalInmillisecods:【用戶控制客戶端自動ping服務器端的時間】。 指如果客戶端在15s內沒有發送任何消息,則15s的時候客戶端會自動ping一下服務器端,從而告訴服務器端,我在線。如果15s內發消息,這個時間間隔將會被重置。
(3). 兩套機制 (實際中,兩套機制相互配合使用)
A. 以客戶端為基准的機制 (客戶端主動進 onclose回調)
客戶端配置:serverTimeoutInMilliseconds + 服務端端配置:keepAliveinterval ,建議serverTimeoutInMilliseconds 的值是 keepAliveinterval 的兩倍,從而保證客戶端不進入 onclose回調,不掉線。
代碼分享:下面代碼的配置就是默認配置,客戶端配置30s沒有收到服務器端發過來的信息,則認為服務器端異常,客戶端掉線,進入onclose回調;服務器端配置為15s沒有向客戶端發送消息,則需要主動ping一下客戶端,按照默認這種Server 15s,Client 30s的配置,在網絡通暢的情況下,客戶端是不會掉線的。
PS:此處如果改個非正常配置,比如客戶端 serverTimeoutInMilliseconds 配置10s,服務器端 keepAliveInterval 配置20s,經測試,你會發現,如果客戶端在10s內沒有收到任何消息,則會吊銷,進入onclose回調。
var connection = new signalR.HubConnectionBuilder().withUrl("http://XXXX:8088/chathub").build(); connection.serverTimeoutInMilliseconds = 30000; //30s
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); //此處是做SignalR的全局配置,也可以去下面的集線器出配置單獨的,單獨的優先級> 此處全局的 services.AddSignalR(hubOptions => { //服務器端向客戶端 ping的間隔 hubOptions.KeepAliveInterval = TimeSpan.FromSeconds(15); }); }
B. 以服務端為基准的機制
客戶端配置:keepAliveIntervalInmillisecods + 服務端配置:clientTimeoutInterval,建議 clientTimeoutInterval 的值是 keepAliveIntervalInmillisecods 的兩倍,從而保證不進服務器端的 OnDisconnectedAsync 回調,即不掉線。
代碼分享:下面代碼是默認配置,客戶端配置15s內沒有向服務器發送任何消息,則自動ping一下服務器端;服務器端配置30s沒有收到客戶端發送的消息,則認為客戶端已經掉線(雖然客戶端此時可能沒有掉線);在網絡通暢的情況下,服務器端是不會進入OnDisconnectedAsync回調的。
var connection = new signalR.HubConnectionBuilder().withUrl("http://XXXX:8088/chathub").build(); connection.keepAliveIntervalInMilliseconds= 15000; //15s
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); //此處是做SignalR的全局配置,也可以去下面的集線器出配置單獨的,單獨的優先級> 此處全局的 services.AddSignalR(hubOptions => { //要求30s內必須收到客戶端發的一條消息,如果沒有收到,那么服務器端則認為客戶端掉了 hubOptions.ClientTimeoutInterval= TimeSpan.FromSeconds(30); }); }
3. 實戰測試結論
PS:要把自動重連的機制關了再測試,否則會干擾,無法進行。
(1). 正常配置下(指滿足前后端大小關系的配置,不必非2倍關系),划掉應用,服務器端會立刻進入 OnDisconnectedAsync 回調。
(2). 正常配置下(指滿足前后端大小關系的配置,不必非2倍關系),客戶端斷網,服務器端會在 clientTimeoutInterval 中配置的時間內 進入 OnDisconnectedAsync回調。
(3). 非正常配置,
服務器端:clientTimeoutInterval = 5s
客戶端:keepAliveIntervalInmillisecods=15s
經測試:客戶端建立連接,發送了一條消息,再不發消息,也不斷網, 這個時候過了 15s, 客戶端會自動ping一下服務器端,然后再過5s,服務器端進入 OnDisconnectedAsync 回調。
下面在分享一下 客戶端和服務器端相互ping的截圖:
(綠色箭頭代表 客戶端ping Server端, 紅色箭頭代表 Server端ping 客戶端)
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。