一、初識Netty

shigp1發表於2024-10-02

Netty是快速開發高效能,高擴充套件性的網路伺服器和客戶端提供的非同步框架。目標有:

  1. 快速輕鬆開發,不僅能快速輕鬆開發tcp,udp程式,還能開發ftp,http外的其他應用層協議。

  2. 高效能,高擴充套件,基於Java的NIO設計了優秀的Reactor模式實現。

這裡選擇Netty4版本。依賴如下:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.113.Final</version>
</dependency>

以一個簡單的服務開始Netty的學習之旅。用Netty實現一個Discard服務:丟棄客戶端傳送的資料,也不向客戶端傳送資料。

public static void startServer(int port) {

        ServerBootstrap serverBootstrap = new ServerBootstrap();

        // 監聽客戶端並接受連線輪詢組
        NioEventLoopGroup bossEventLoppGroup = new NioEventLoopGroup();

        //工作輪詢組
        NioEventLoopGroup workEventLoppGroup = new NioEventLoopGroup();

        try {
            // 1、設定輪詢組
            ChannelFuture channelFuture = serverBootstrap.group(bossEventLoppGroup, workEventLoppGroup)
                    // 2、設定NIO型別通道
                    .channel(NioServerSocketChannel.class)
                    // 3、設定監聽埠
                    .localAddress(new InetSocketAddress("localhost",port))
                   // 4、設定通道引數
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                   // 5、裝配子通道流水線
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                            nioSocketChannel.pipeline().addLast(new DiscardHandle());
                        }
                    })
                    // 6、繫結伺服器
                    .bind();

            ChannelFuture sync = channelFuture.sync();

            System.out.println("伺服器啟動成功,繫結埠"+sync.channel().localAddress());


            // 7、等待通道非同步關閉
            sync.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 8 、釋放資源
            bossEventLoppGroup.shutdownGracefully();
            workEventLoppGroup.shutdownGracefully();
        }

    }

//ChannelInboundHandlerAdapter是ChannelInboundHandler的預設實現
public class DiscardHandle extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf) msg;

        System.out.println("收到訊息如下");

        try {
            while (byteBuf.isReadable()) {
                System.out.print((char) byteBuf.readByte());
            }
            System.out.println();
        } finally {
            ReferenceCountUtil.release(byteBuf);
        }
    }
}

ServerBootstrap負責Netty元件的組裝,配置,Netty伺服器或客戶端的啟動。也可以不用ServerBootstrap,而由自己負責這些工作。

1、第一步建立了兩個反映器輪詢組。回顧下Reactor模式,這裡的輪詢組實現了Reactor模式中Reactor執行緒的工作。第一個輪詢組叫作boss輪詢組,負責監聽並連線客戶端,也叫做“包工頭”,第二個輪詢組叫做工作輪詢組,負責資料的傳輸及處理。也可以直接用一個輪詢組。反映器輪詢組與Reactor模式中的Reactor執行緒不同,一個輪詢組中有一個執行緒池,裡面的每個執行緒相當於Reactor模式中的Reactor執行緒。

2、設定通道的型別。Netty不止支援NIO,也支援BIO,還可以配置為OioServerSocketChannel。

3、設定監聽埠。

4、設定通道的引數。注意第4步,第5步的方法名,有child。為什麼要這麼命名?因為有父子通道的概念。在Linux系統中,NioServerSocketChannel包裝了Linux系統中的檔案描述符,這個檔案描述符負責監聽客戶端的連線。NioSocketChannel也包裝了Linux系統中的檔案描述符,負責資料傳輸及處理。NioServerSocketChannel叫做NioSocketChannel的父通道,NioSocketChannel叫NioServerSocketChannel的子通道。注意第4步,第5步的方法名設定的都是子通道中的屬性。所以要有child。

這些引數一般都是與TCP協議相關的。

SO_KEEPALIVE:是否開啟TCP的心跳機制,true為連線保持心跳,false為關閉。

SO_SNDBUF:TCP在核心中的傳送緩衝區大小

SO_RCVBUF:TCP在核心中的接收緩衝區大小

TCP_NODELAY:是否開啟Nagle演算法,為true,關閉Nagle演算法,馬上傳送資料。為false,開啟Nagle演算法,等資料積累緩衝區在傳送。

SO_BACKLOG:TCP三次握手時接收連線的佇列長度。

SO_LINGER:-1表示socket.close呼叫後立即返回,作業系統會將緩衝區的資料全部傳送。0表示socket.close呼叫後立即返回,作業系統會放棄傳送緩衝區的資料。非0的整數表示socket.close呼叫後被阻塞直到超時(數字表示超時時間)傳送緩衝區資料,若超時,接收端收到錯誤。

5、裝配子通道的Pipleline。伺服器接受客戶端的連線後,會呼叫此方法設定channel的Pipeline,Pipeline是個雙向連表,裡面儲存了ChannelInboundHandler(入站處理器,主要負責讀取)和ChannelOutboundHandler(出站處理器,主要負責寫入)。

入站處理器是從前往後執行,如果後面還有入站處理器,將IO事件交給下一個入站處理器處理。否則將結束。

出站處理器是從後往前執行。

6、繫結伺服器,並啟動。注意觀察。bind方法的返回值是ChannelFuture,,是非同步的,呼叫了sync讓它同步執行繫結成功。

7、獲取closeFuture關閉通道,並等待監聽通道關閉。

8、釋放資源。輪詢組內的執行緒,Selector,子通道都會被關閉。

相關文章