<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Netty的心跳機(jī)制

          共 2198字,需瀏覽 5分鐘

           ·

          2022-02-24 16:44

          一、引入

          在 TCP 保持長(zhǎng)連接的過(guò)程中,可能會(huì)出現(xiàn)斷網(wǎng)等網(wǎng)絡(luò)異常出現(xiàn),異常發(fā)生的時(shí)候, client 與 server 之間如果沒(méi)有交互的話(huà),它們是無(wú)法發(fā)現(xiàn)對(duì)方已經(jīng)掉線(xiàn)。

          二、工作原理

          在 client 與 server 之間在一定時(shí)間內(nèi)沒(méi)有數(shù)據(jù)交互時(shí), 即處于 idle 狀態(tài)時(shí), 客戶(hù)端或服務(wù)器就會(huì)發(fā)送一個(gè)特殊的數(shù)據(jù)包給對(duì)方, 當(dāng)接收方收到這個(gè)數(shù)據(jù)報(bào)文后, 也立即發(fā)送一個(gè)特殊的數(shù)據(jù)報(bào)文, 回應(yīng)發(fā)送方, 此即一個(gè) PING-PONG 交互。所以, 當(dāng)某一端收到心跳消息后, 就知道了對(duì)方仍然在線(xiàn), 這就確保 TCP 連接的有效性。

          TCP 實(shí)際上自帶的就有長(zhǎng)連接選項(xiàng),本身是也有心跳包機(jī)制,也就是 TCP 的選項(xiàng):SO_KEEPALIVE。但是,TCP 協(xié)議層面的長(zhǎng)連接靈活性不夠。所以,一般情況下我們都是在應(yīng)用層協(xié)議上實(shí)現(xiàn)自定義心跳機(jī)制的,也就是在 Netty 層面通過(guò)編碼實(shí)現(xiàn)。通過(guò) Netty 實(shí)現(xiàn)心跳機(jī)制的話(huà),核心類(lèi)是 IdleStateHandler 。

          三、實(shí)現(xiàn)

          在?Netty中, 實(shí)現(xiàn)心跳機(jī)制的關(guān)鍵是?IdleStateHandler

          public IdleStateHandler(int readerIdleTimeSeconds, int writerIdleTimeSeconds, int allIdleTimeSeconds) {
          this((long)readerIdleTimeSeconds, (long)writerIdleTimeSeconds, (long)allIdleTimeSeconds, TimeUnit.SECONDS);
          }

          參數(shù)的含義:

          ?readerIdleTimeSeconds: 讀超時(shí). 即當(dāng)在指定的時(shí)間間隔內(nèi)沒(méi)有從?Channel?讀取到數(shù)據(jù)時(shí), 會(huì)觸發(fā)一個(gè)?READER_IDLE?的?IdleStateEvent?事件.?writerIdleTimeSeconds: 寫(xiě)超時(shí). 即當(dāng)在指定的時(shí)間間隔內(nèi)沒(méi)有數(shù)據(jù)寫(xiě)入到?Channel?時(shí), 會(huì)觸發(fā)一個(gè)?WRITER_IDLE?的?IdleStateEvent?事件.?allIdleTimeSeconds: 讀/寫(xiě)超時(shí). 即當(dāng)在指定的時(shí)間間隔內(nèi)沒(méi)有讀或?qū)懖僮鲿r(shí), 會(huì)觸發(fā)一個(gè)?ALL_IDLE?的?IdleStateEvent?事件.

          注意:這三個(gè)參數(shù)默認(rèn)的時(shí)間單位是秒。

          心跳處理類(lèi):ClientIdleStateTrigger

          /**
          * <p>
          * 用于捕獲{@link IdleState#WRITER_IDLE}事件(未在指定時(shí)間內(nèi)向服務(wù)器發(fā)送數(shù)據(jù)),然后向Server端發(fā)送一個(gè)心跳包。
          * p>
          */
          public class ClientIdleStateTrigger extends ChannelInboundHandlerAdapter {

          public static final String HEART_BEAT = "heart beat!";

          @Override
          public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
          if (evt instanceof IdleStateEvent) {
          IdleState state = ((IdleStateEvent) evt).state();
          if (state == IdleState.WRITER_IDLE) {
          // write heartbeat to server
          ctx.writeAndFlush(HEART_BEAT);
          }
          } else {
          super.userEventTriggered(ctx, evt);
          }
          }

          }

          四、源碼剖析

          0fdd3f0352633d97db052d33a0a2fcfd.webp

          第254行代碼其實(shí)表示該方法只是進(jìn)行了透?jìng)鳎蛔鋈魏螛I(yè)務(wù)邏輯處理,讓channelPipe中的下一個(gè)handler處理channelRead方法,但是記錄了一下這里的調(diào)用時(shí)間

          channelActive方法

          a1da72a5ac27896d86ac36c2c9e7e19b.webp

          initialize方法

          a1b390082fc9c7b3d548896151679297.webp

          這邊會(huì)觸發(fā)一個(gè)Task,ReaderIdleTimeoutTask,這個(gè)task是部分源碼

          e4e62b4ff89d712cd34df6b315edabb4.webp

          341行是這樣的,用當(dāng)前時(shí)間減去最后一次channelRead方法調(diào)用的時(shí)間,假如這個(gè)結(jié)果是6s,說(shuō)明最后一次調(diào)用channelRead已經(jīng)是6s之前的事情了,你設(shè)置的是5s,那么nextDelay則為-1,說(shuō)明超時(shí)了,那么354行則會(huì)觸發(fā)userEventTriggered方法,如果沒(méi)有超時(shí)則不觸發(fā)userEventTriggered方法。

          47c87b3afb951b662f2fbc135abbb746.webp

          五、總結(jié)

          IdleStateHandler這個(gè)類(lèi)會(huì)根據(jù)你設(shè)置的超時(shí)參數(shù)的類(lèi)型和值,循環(huán)去檢測(cè)channelReadwrite方法多久沒(méi)有被調(diào)用了,如果這個(gè)時(shí)間超過(guò)了你設(shè)置的值,那么就會(huì)觸發(fā)對(duì)應(yīng)的事件,read觸發(fā)read,write觸發(fā)write,all觸發(fā)all

          ?如果超時(shí)了,則會(huì)調(diào)用userEventTriggered方法,且會(huì)告訴你超時(shí)的類(lèi)型?如果沒(méi)有超時(shí),則會(huì)循環(huán)定時(shí)檢測(cè),除非你將IdleStateHandler移除Pipeline


          瀏覽 41
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产成人777777精品综合 | 精品白浆| 收各种流量价格置顶TG@DJYT8 | 国产欧美青青 | 一级一级人与动毛片 |