第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

Netty 斷開重連

1. 前言

上節(jié),我們主要講解了 Netty 的心跳檢測機制,其中核心目的是提高性能。本節(jié)我們主要講解的是 Netty 長連接的穩(wěn)定性。

2. 學(xué)習(xí)目的

TCP 協(xié)議下,數(shù)據(jù)是可以雙向傳遞,其實也就是全雙工協(xié)議,通俗點來說就是長連接,只要客戶端和服務(wù)端連接之后,雙方可以正常通行,那么長連接是否存在什么不穩(wěn)定性呢?

在長連接情況下,通常面臨的情況就是網(wǎng)絡(luò)問題,網(wǎng)絡(luò)抖動造成的連接假死,舉個例子:其實客戶端和服務(wù)端的 TCP 連接已經(jīng)斷開,但是雙方?jīng)]有監(jiān)聽到,認為該連接仍然是有效的。

這樣的問題會導(dǎo)致以下幾個后果,如下所示:

  1. 客戶端往服務(wù)端發(fā)送消息時,由于連接已經(jīng)斷開,會導(dǎo)致請求超時,影響用戶體驗;
  2. 服務(wù)端往客戶端推送消息時,由于連接已經(jīng)斷開,導(dǎo)致連接推送失??;
  3. 每條連接都消耗 cpu 和內(nèi)存資源,大量的假死會導(dǎo)致服務(wù)器資源消耗,導(dǎo)致服務(wù)器卡頓甚至宕機。

3. 連接面臨問題及解決方案

圖片描述

4. 連接假死

4.1 產(chǎn)生的原因

連接已經(jīng)斷開,但是程序沒有捕捉的到,認為連接還存在,產(chǎn)生的原因大致如下:

  1. 應(yīng)用程序內(nèi)部線程堵塞,導(dǎo)致數(shù)據(jù)讀寫也會堵塞;
  2. 網(wǎng)絡(luò)抖動,數(shù)據(jù)丟包等,發(fā)送方一種發(fā)送不出數(shù)據(jù),接收方也收不到數(shù)據(jù),連接就一直的耗著;
  3. 公網(wǎng)相對內(nèi)網(wǎng)來說不是很穩(wěn)定,受到的干擾更多,故障的概率也會增大。

4.2 解決辦法

問題: 服務(wù)端 5 秒鐘沒用讀取數(shù)據(jù)事件,那么是否一定是假死呢?

回答: 不一定,主要有兩種情況,①連接假死;②連接空閑。

針對連接假死的解決方案

主要是通過心跳檢測去監(jiān)控,如果指定時間之內(nèi),服務(wù)端沒有收到客戶端的數(shù)據(jù),則主動斷開連接,杜絕了連接假死現(xiàn)象。

針對連接空閑狀態(tài)的解決方案

情況一: 如果對通信的實時性要求不高,并且對性能要求很高的情況,可以直接斷開連接,等待有需要的時候,再重新連接(這個是上節(jié)已經(jīng)講解過了,適合客戶端主動的業(yè)務(wù)場景,比如:IM);
情況二: 如果對通信的實時性要求很高,則不能斷開連接(比如:消息推送),為了保證連接能夠存活而不被心跳檢測機制自動斷開。

針對情況二的解決方案如下:

  1. 定時發(fā)送空包,并且時間間隔小于心跳檢測時間間隔,保證連接存活;
  2. 如果連接真的斷開了,則客戶端監(jiān)聽事件 channelInactive () 里面實現(xiàn)斷開重連;

總結(jié),這種模式的好處有兩點,①保證連接能夠長時間存活,避免錯過重要消息;②避免連接空閑時,頻繁的斷開和重連,浪費資源。

其中,心跳檢測上節(jié)以及詳細講解了,這里主要講解一下發(fā)送空包數(shù)據(jù)和斷開重連如何實現(xiàn)。

5. 代碼實現(xiàn)

5.1 服務(wù)端心跳檢測

實例:

ChannelPipeline pipeline = ch.pipeline();
//5秒鐘之內(nèi)沒有 讀事件 則斷開連接
pipeline.addLast(new ReadTimeoutHandler(5, TimeUnit.SECONDS));

//字符串解碼器
pipeline.addLast(new StringDecoder());

//字符串編碼器
pipeline.addLast(new StringEncoder());

//業(yè)務(wù)Handler
pipeline.addLast(new HeartBeatHandler());

代碼說明:

服務(wù)端主要是監(jiān)聽讀事件,每隔 5 秒讀取不到數(shù)據(jù),則認為連接無效,主動斷開連接。

5.2 客戶端定時發(fā)送空包

實例:

public class HeartBeatTimerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //發(fā)送空包
        scheduleSendHeartBeat(ctx);
    }

    private void scheduleSendHeartBeat(ChannelHandlerContext ctx) {
        ctx.executor().schedule(() -> {
            if (ctx.channel().isActive()) {
                //發(fā)送空包(定義一個實體)
                ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);
            }

        }, 3, TimeUnit.SECONDS);
    }
}

代碼說明:

  1. 借助 EventLoop 的定時線程池去實現(xiàn)每隔 3 秒鐘發(fā)送一個空包;
  2. 空包數(shù)據(jù),自定義一個實體即可;
  3. 主要的是空包的時間間隔(3s)一定要小于心跳監(jiān)聽的時間間隔(5s)。

5.3 客戶端斷開重連

實例:

//字符串解碼器
pipeline.addLast(new StringDecoder());
//字符串編碼器
pipeline.addLast(new StringEncoder());
//業(yè)務(wù)Handler,需要傳遞“bootstrap”
pipeline.addLast(new ClientHandler(bootstrap));
public class ClientHandler extends ChannelInboundHandlerAdapter {
    private Bootstrap bootstrap;
    ClientHandler(Bootstrap bootstrap){
        this.bootstrap=bootstrap;
    }
	
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		bootstrap.connect("127.0.0.1",80).sync();
    }
}

代碼說明:

  1. 連接斷開時,客戶端的 Handler 的 channelInactive () 會監(jiān)聽的到,在該方法里面實現(xiàn)斷開重連;
  2. Handler 必須傳遞 bootstrap。

6. 小結(jié)

本節(jié)主要講解了基于心跳檢測的基礎(chǔ)上實現(xiàn)了空包發(fā)送和斷開重連的功能,主要核心意圖有兩個

  1. 空包發(fā)送: 讓連接能夠長時間的存活,而避免空閑連接收到心跳檢測的干擾;同時還避免了心跳檢測導(dǎo)致的頻繁的斷開和重連,導(dǎo)致資源浪費;
  2. 斷開重連: 讓連接一直在線,保證了連接的穩(wěn)定性。