第七節:Core SignalR中的重連機制和心跳監測機制詳解


一. 重連機制

聲明:
  本節僅介紹重連機制和心跳監測機制,基於Core 3.1框架,至於SignalR其它的一些基本使用,包括引入、Hub、配置等常規操作,在本節中不介紹,后續寫Core下的SignalR

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 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM