連接管理 與 Netty 心跳機制


一、前言

踏踏實實,動手去做,talk is cheap, show me the code。先介紹下基礎知識,然后做個心跳機制的Demo。

 

二、連接

長連接:在整個通訊過程,客戶端和服務端只用一個Socket對象,長期保持Socket的連接;短連接:每次請求,都新建一個Socket,處理完一個請求就直接關閉掉Socket。所以,其實區分二者就是:整個客戶和服務端的通訊過程是利用一個Socket還是多個Socket進行的。一般,長連接多用於數據發送頻繁,點對點的通訊。因為TCP連接都需要握手,這很花費時間,有時建立連接的時間有可能比業務傳輸的時間要多。

客戶端不主動斷開連接,並不是說連接就不會斷。比如:客戶端突然斷電、網線故障、空閑的Socket被防火牆自動關閉、系統崩潰等,服務端無法檢測到連接的斷開,因此需要對長連接進行管理。

保活的兩種方式:

①TCP協議自帶的keep-alive功能

★系統內核自動替上層做好

★內核層面計時器相比上冊應用更高效

★數據包更緊湊,數據量更小

★默認的心跳時間是2小時,依賴操作系統實現不夠靈活

②應用層的keep-alive,一般叫做心跳包機制

(TCP長連接中,客戶端和服務端定時向對方發送數據包通知自己還在線,保證連接有效性的機制)

★完全使用業務層面的心跳保活機制

★更大靈活性,可以自己控制檢測的參數,如檢測的時間間隔、檢測的方式等

★不依賴協議,心跳包同時適用於TCP和UDP

因此如果你們能確定更換協議的可能性非常小, 同時只是需要檢活的功能, 那么用協議自帶的就可以了, 使用簡單而且高效。

 

三、Netty 心跳連接

1.基於 IdleStateHandler

首先我們要知道,在服務器和客戶端之間,一段時間內沒有數據交互時,即處於Idle狀態。下面是通過Netty IdleStateHandler來實現心跳機制。

使用方法:

(code摘自Netty api 文檔  https://netty.io/4.0/api/io/netty/handler/timeout/IdleStateHandler.html )

 1  public class MyChannelInitializer extends ChannelInitializer<Channel> {
 2       @Override
 3      public void initChannel(Channel channel) {
 4          channel.pipeline().addLast("idleStateHandler", new IdleStateHandler(60, 30, 0));
// IdleStateHandler的構造方法有三個參數,監控讀、監控寫、監控讀與寫、觸發心跳機制的時間間隔(單位,秒)
// 0 表示 disable
5 channel.pipeline().addLast("myHandler", new MyHandler()); 6 } 7 } 8 9 // Handler should handle the IdleStateEvent triggered by IdleStateHandler. 10 public class MyHandler extends ChannelDuplexHandler { 11 @Override 12 public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 13 if (evt instanceof IdleStateEvent) { 14 IdleStateEvent e = (IdleStateEvent) evt; 15 if (e.state() == IdleState.READER_IDLE) { 16 ctx.close(); 17 } else if (e.state() == IdleState.WRITER_IDLE) { 18 ctx.writeAndFlush(new PingMessage()); 19 } 20 } 21 } 22 } 23 24 ServerBootstrap bootstrap = ...; 25 ... 26 bootstrap.childHandler(new MyChannelInitializer()); 27 ... 28

 2.基於keep-alive

分別開啟keep-alive功能即可

服務端:

b.group(group).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
                    .childOption(ChannelOption.SO_KEEPALIVE, true).handler(new LoggingHandler(LogLevel.INFO))
                    .localAddress(new InetSocketAddress(port)).childHandler(new ChannelInitializer<SocketChannel>() {

客戶端:

bootstrap.group(group).channel(NioSocketChannel.class).option(ChannelOption.SO_KEEPALIVE, true)
                    .remoteAddress(new InetSocketAddress(host, port)).handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel channel) throws Exception {
                            channel.pipeline().addLast(new EchoClientHandler());
                        }
                    });

 

參考資料:

https://www.cnblogs.com/my_life/articles/4045696.html

https://blog.csdn.net/u013967175/article/details/78591810

https://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/

https://blog.csdn.net/linuu/article/details/51404264

 


免責聲明!

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



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