1. 程式人生 > >Netty(三)建立服務端

Netty(三)建立服務端

1、服務端時序圖:

 

2、編碼流程:

  1. 建立ServerBootstrap例項
  2. 設定EventLoopGroup
  3. 設定建立的Channel型別
  4. option配置屬性
  5. 設定Handler,處理請求
  6. 設定ChildHandler,處理對應channel的請求
  7. 通過bind建立Chnnel並繫結,啟動服務
serverBootstrap = new ServerBootstrap();
eventLoopGroup = new NioEventLoopGroup();

serverBootstrap.group(eventLoopGroup)
               .channel(NioServerSocketChannel.class)
               .option(ChannelOption.SO_KEEPALIVE, true)
               .handler(new LoggingHandler(LogLevel.INFO));

 設定Handler,處理請求

 設定ChildHandler,處理對應channel的請求

 通過bind建立Chnnel並繫結,啟動服務

 serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel sc) throws Exception {
                sc.pipeline()
                        .addLast(new ProtocolDecoder(chargeDevice))
                        .addLast(new ProtocolEncoder())
                        .addLast(new IdleStateHandler(readerIdleTime, writerIdleTime, allIdleTime, TimeUnit.SECONDS))
                        .addLast(new MyInboundHandler(chargeDevice));
            }
        });
        this.channelFuture = serverBootstrap.bind(port).sync();

3、服務端重要元件

(1)ServerBootstrap
ServerBootstrap是Netty服務端的啟動輔助類,提供一系列的方法用於設定服務端的引數和配置,簡化開發。(衍生一點:ServerBootstrap的構造方法是無參的,因為引數太多所以採用了Builder模式)

繼承自AbstractBootstrap,核心屬性有childGroup和childHandler。

  • childGroup:負責排程和執行客戶端的接入、網路讀寫事件的處理、使用者自定義任務和定時任務的執行
  • childHandler:自定義的業務Handler

AbstractBootstrap核心屬性有group和handler。

  • group:處理客戶端的連結請求,並轉交給childGroup(讀取的資料是穿件的NioSocketChannel)

(2)Reactor執行緒池
Netty的Reactor執行緒池是EventLoopGroup,實際上是一個EventLoop的陣列。

EventLoop的職責是處理所有註冊到本執行緒多路複用器Selector上的Channel,Selector的輪訓操作有EventLoop執行緒run方法驅動。

另外使用者自定義的Task和定時任務Task也由統一的EventLoop負責處理。

(3)Channel
作為Nio服務,需要建立ServerSocketChannel,Netty對原生NIO類庫做了封裝,對應實現類為NioServerSocketChannel。

使用者只需要制定Channel的實現型別,內部通過反射機制來建立對應的例項。

因為只在監聽埠時建立,所以反射的效能影響並不大。

(4)ChannelPipeline
ChannelPipeline是網路事件處理的職責鏈,負責管理和執行ChannelHandler。網路事件以事件流的形式在ChannelPipeline中流轉。

(5)ChannelHandler
ChannelHandler是提供給使用者定製和擴充套件的關鍵介面,包括編解碼,業務處理等都是通過ChannelHandler進行的。

(6)Selector
Selector輪訓操作由NioEventLoop排程和執行,選擇準備就緒的Channel集合。

(7)NioServerSocketChannel
繫結Server端地址的Server,讀取客戶端的連結請求(只有一個,在bind時建立)。

(8)NioSocketChannel
和客戶端之間的連結。

4、例項

public class NettyServer {

    public void bind(int port){
        // 建立EventLoopGroup
        EventLoopGroup bossGroup = new NioEventLoopGroup();        //建立BOSS執行緒組 用於服務端接受客戶端的連線
        EventLoopGroup workerGroup = new NioEventLoopGroup();      //建立WORK執行緒組 用於進行SocketChannel的網路讀寫

        try {
            // 建立ServerBootStrap例項
            // ServerBootstrap 用於啟動NIO服務端的輔助啟動類,目的是降低服務端的開發複雜度
            ServerBootstrap b = new ServerBootstrap();
            // 繫結Reactor執行緒池
            b.group(bossGroup, workerGroup)
                    // 設定並繫結服務端Channel
                    // 指定所使用的NIO傳輸的Channel
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .handler(new LoggingServerHandler())
                    .childHandler(new ChannelInitializer(){

                        @Override
                        protected void initChannel(Channel ch) throws Exception {
                            //do something
                        }
                    });

            // 繫結埠,同步等待成功
            ChannelFuture future = b.bind(port).sync();
            // 等待服務端監聽埠關閉
            future.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 優雅地關閉
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private class LoggingServerHandler extends ChannelInboundHandlerAdapter{
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            System.out.println("loggin-channelActive");
        }

        @Override
        public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
            System.out.println("loggin-channelRegistered");
        }

        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            System.out.println("loggin-handlerAdded");
        }
    }

    public static void main(String[] args){
            new NettyServer().bind(8899);
    }
}