Netty服務(wù)端和客戶端創(chuàng)建的源碼分析

<h2>服務(wù)端</h2>

以下是Netty官方的一個(gè)Echo服務(wù)示例:

public final class EchoServer {

    static final boolean SSL = System.getProperty("ssl") != null;
    static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));

    public static void main(String[] args) throws Exception {
        // Configure SSL.
        final SslContext sslCtx;
        if (SSL) {
            SelfSignedCertificate ssc = new SelfSignedCertificate();
            sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
        } else {
            sslCtx = null;
        }

        // Configure the server.
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .option(ChannelOption.SO_BACKLOG, 100)
             .handler(new LoggingHandler(LogLevel.INFO))
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                     if (sslCtx != null) {
                         p.addLast(sslCtx.newHandler(ch.alloc()));
                     }
                     //p.addLast(new LoggingHandler(LogLevel.INFO));
                     p.addLast(new EchoServerHandler());
                 }
             });
  
            // Start the server.
            ChannelFuture f = b.bind(PORT).sync();
  
            // Wait until the server socket is closed.
            f.channel().closeFuture().sync();
        } finally {
            // Shut down all event loops to terminate all threads.
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
        
    }
}

上面代碼創(chuàng)建Server端服務(wù)的流程如下:

  1. 創(chuàng)建ServerBootstrap實(shí)例
  2. 設(shè)置EventLoopGroup
  3. 設(shè)置創(chuàng)建的Channel類型
  4. option配置屬性
  5. 設(shè)置Handler,處理請(qǐng)求
  6. 設(shè)置ChildHandler,處理對(duì)應(yīng)channel的請(qǐng)求
  7. 通過(guò)bind創(chuàng)建Chnnel并綁定,啟動(dòng)服務(wù)

服務(wù)端創(chuàng)建時(shí)序圖

服務(wù)端重要組件
ServerBootstrap
ServerBootstrap是Netty服務(wù)端的啟動(dòng)輔助類,提供一系列的方法用于設(shè)置服務(wù)端的參數(shù)和配置,簡(jiǎn)化開(kāi)發(fā)。(衍生一點(diǎn):ServerBootstrap的構(gòu)造方法是無(wú)參的,因?yàn)閰?shù)太多所以采用了Builder模式)

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

  • childGroup:負(fù)責(zé)調(diào)度和執(zhí)行客戶端的接入、網(wǎng)絡(luò)讀寫(xiě)事件的處理、用戶自定義任務(wù)和定時(shí)任務(wù)的執(zhí)行
  • childHandler:自定義的業(yè)務(wù)Handler

AbstractBootstrap核心屬性有g(shù)roup和handler。

  • group:處理客戶端的鏈接請(qǐng)求,并轉(zhuǎn)交給childGroup(讀取的數(shù)據(jù)是穿件的NioSocketChannel)

Reactor線程池
Netty的Reactor線程池是EventLoopGroup,實(shí)際上是一個(gè)EventLoop的數(shù)組。

EventLoop的職責(zé)是處理所有注冊(cè)到本線程多路復(fù)用器Selector上的Channel,Selector的輪訓(xùn)操作有EventLoop線程run方法驅(qū)動(dòng)。

另外用戶自定義的Task和定時(shí)任務(wù)Task也由統(tǒng)一的EventLoop負(fù)責(zé)處理。

Channel
作為Nio服務(wù),需要?jiǎng)?chuàng)建ServerSocketChannel,Netty對(duì)原生NIO類庫(kù)做了封裝,對(duì)應(yīng)實(shí)現(xiàn)類為NioServerSocketChannel。

用戶只需要制定Channel的實(shí)現(xiàn)類型,內(nèi)部通過(guò)反射機(jī)制來(lái)創(chuàng)建對(duì)應(yīng)的實(shí)例。

因?yàn)橹辉诒O(jiān)聽(tīng)端口時(shí)創(chuàng)建,所以反射的性能影響并不大。

ChannelPipeline
ChannelPipeline是網(wǎng)絡(luò)事件處理的職責(zé)鏈,負(fù)責(zé)管理和執(zhí)行ChannelHandler。網(wǎng)絡(luò)事件以事件流的形式在ChannelPipeline中流轉(zhuǎn)。

ChannelHandler
ChannelHandler是提供給用戶定制和擴(kuò)展的關(guān)鍵接口,包括編解碼,業(yè)務(wù)處理等都是通過(guò)ChannelHandler進(jìn)行的。

Selector
Selector輪訓(xùn)操作由NioEventLoop調(diào)度和執(zhí)行,選擇準(zhǔn)備就緒的Channel集合。

NioServerSocketChannel
綁定Server端地址的Server,讀取客戶端的鏈接請(qǐng)求(只有一個(gè),在bind時(shí)創(chuàng)建)。

NioSocketChannel
和客戶端之間的鏈接。

服務(wù)端線程模型

  • mainReactor:parentGroup
  • subReactor:childGroup
  • ThreadPool:如果沒(méi)指定,使用childGroup執(zhí)行,如果指定了則是業(yè)務(wù)線程(執(zhí)行業(yè)務(wù)Handler的線程)

Handler模型

Server啟動(dòng)的關(guān)鍵流程

  1. bind操作創(chuàng)建了NioServerSocketChannel并注冊(cè)到NioEventLoop中(parent group中會(huì)有一個(gè)線程執(zhí)行selector的輪訓(xùn)操作)

Server端的請(qǐng)求接入流程

  1. NioEventLoop輪訓(xùn)到到就緒時(shí)間后,調(diào)用Unsafe.read(NioMessageUnsafe實(shí)現(xiàn))創(chuàng)建NioSocketChannel并傳遞到ServerBootstrap的ServerBootstrapAcceptor的channelRead方法中。
  2. ServerBootstrapAcceptor的channelRead方法將NioSocketChannel注冊(cè)到childGroup的Selector上(實(shí)現(xiàn)代碼是AbstractNioSocket的doRegister;之后NioSocketChannel的事件就由child group處理,這點(diǎn)和NioServerSocketChannel的注冊(cè)、處理是一樣的;和上面的線程模型也是呼應(yīng)的:兩個(gè)reactor)。

<h2>客戶端</h2>

public static void main(String[] args) throws Exception {
    // Configure SSL.git
    final SslContext sslCtx;
    if (SSL) {
        sslCtx = SslContextBuilder.forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
    } else {
        sslCtx = null;
    }

    // Configure the client.
    EventLoopGroup group = new NioEventLoopGroup();
    try {
        Bootstrap b = new Bootstrap();
        b.group(group)
         .channel(NioSocketChannel.class)
         .option(ChannelOption.TCP_NODELAY, true)
         .handler(new ChannelInitializer<SocketChannel>() {
             @Override
             public void initChannel(SocketChannel ch) throws Exception {
                 ChannelPipeline p = ch.pipeline();
                 if (sslCtx != null) {
                     p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
                 }
                 //p.addLast(new LoggingHandler(LogLevel.INFO));
                 p.addLast(new EchoClientHandler());
             }
         });

        // Start the client.
        ChannelFuture f = b.connect(HOST, PORT).sync();

        // Wait until the connection is closed.
        f.channel().closeFuture().sync();
    } finally {
        // Shut down the event loop to terminate all threads.
        group.shutdownGracefully();
    }
}

創(chuàng)建客戶端的大致流程:

  1. 創(chuàng)建Bootstrap實(shí)例
  2. 設(shè)置EventLoop
  3. 指定Channel類型
  4. option配置
  5. 指定Handler
  6. connect

客戶端創(chuàng)建時(shí)序圖

客戶端和服務(wù)端的模式基本一致,由線程輪訓(xùn)Selector的事件,由Pipeline進(jìn)行事件傳遞,EventLoop進(jìn)行處理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容