Netty 系列文章之基本元件概覽

pjmike_pj發表於2019-03-02

前言

在之前的文章Netty 入門初體驗簡單介紹了 Netty 服務端和客戶端的例子,下面依舊以Netty 服務端 demo 為例,來簡單闡述下 Netty 的基本元件。

基本元件概覽

以Netty服務端的一個例子來闡述其中用到的基本元件,程式碼如下:

public class EchoServer {
    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) throws InterruptedException {
        new EchoServer(8888).start();
    }

    public void start() throws InterruptedException {
        final EchoServerHandler serverHandler = new EchoServerHandler();
        //建立EventLoopGroup,處理事件
        EventLoopGroup group = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(group,worker)
                    //指定所使用的NIO傳輸 Channel
                    .channel(NioServerSocketChannel.class)
                    //使用指定的埠設定套接字地址
                    .localAddress(new InetSocketAddress(port))
                    //新增一個EchoServerHandler到子Channel的ChannelPipeline
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            //EchoServerHandler別標誌為@Shareable,所以我們可以總是使用同樣的例項
                            socketChannel.pipeline().addLast(serverHandler);
                        }
                    });
            //非同步的繫結伺服器,呼叫sync()方法阻塞等待直到繫結完成
            ChannelFuture future = b.bind().sync();
            future.channel().closeFuture().sync();
        } finally {
            //關閉EventLoopGroup,釋放所有的資源
            group.shutdownGracefully().sync();
            worker.shutdownGracefully().sync();
        }
    }
}

複製程式碼

服務端建立流程:

  • 建立 ServerBootStrap例項
  • 設定並繫結 NioEventLoopGroup執行緒池
  • 通過 ServerBootStrapchannel方法設定並繫結服務端 Channel
  • 建立並初始化 ChannelPipeline
  • 新增並設定 ChannelHandler
  • 繫結並啟動監聽埠

上面簡述了服務端的建立流程,其中包含了 Netty的基本元件的使用,下面這張導圖也簡單的敘述了Netty各大元件的概念與作用

netty

Channel

Channel是 Netty中的網路操作抽象類,對應JDK底層的Socket,它除了包含基本的I/O操作,如 bind(),connect(),read(),write()之外,還包括了Netty框架相關的一些功能,如獲取 Channel的EventLoop。

EventLoop

EventLoop定義了Netty的核心抽象,用於處理連線的生命週期中所發生的事件。EventLoop 為Channel處理I/O操作,下圖是 Channel,EventLoop,Thread以及EventLoopGroup之間的關係(摘自《Netty In Action》):

eventloop

這些關係是:

  • 一個EventLoopGroup 包含一個或者多個EventLoop
  • 一個 EventLoop 在它的生命週期內只和一個Thread繫結
  • 所有由 EventLoop處理的 I/O事件都將在它專有的Thread上被處理
  • 一個 Channel 在它的生命週期內只註冊一個EventLoop
  • 一個 EventLoop 可能會被分配給一個或多個 Channel

EventLoopGroup實際上就是處理I/O操作的執行緒池,負責為每個新註冊的Channel分配一個EventLoop,Channel在整個生命週期都有其繫結的 EventLoop來服務。

而上面服務端用的 NioEventLoop 就是 EventLoop的一個重要實現類,NioEventLoop 是Netty內部的I/O執行緒,而 NioEventLoopGroup是擁有 NioEventLoop的執行緒池,在Netty服務端中一般存在兩個這樣的NioEventLoopGroup執行緒池,一個 "Boss" 執行緒池,用於接收客戶端連線,實際上該執行緒池中只有一個執行緒,一個 "Worker"執行緒池用於處理每個連線的讀寫。而Netty客戶端只需一個執行緒池即可,主要用於處理連線中的讀寫操作。

ChannelHandler

ChannelHandler是Netty的主要元件,它主要用於對出站和入站資料進行處理,它有兩個重要的子介面:

  • ChannelInboundHandler——處理入站資料以及各種狀態變化
  • ChannelOutboundHandler——處理出站資料並且允許攔截所有的操作

ChannelPipeline

ChannelPipeline提供了 ChannelHandler鏈的容器,換句話說,就是一個邏輯處理鏈,用於攔截流經Channel的入站和出站事件的ChannelHandler。還是就是當 Channel被建立時,它會被自動地分配到它的專屬的 ChannelPipeline。

channelpipline

當一個訊息或者任何其他的入站事件被讀取時,那麼它會從 ChannelPipeline的頭部開始流動,並被傳遞給第一個 ChannelInboundHandler,第一個處理完成之後傳遞給下一個 ChannelInboundHandler,一直到ChannelPipeline的尾端,與之對應的是,當資料被寫出時,資料從 ChannelOutboundHandler 鏈的尾端開始流動,直到它到達鏈的頭部為止。

ChannelFuture

Netty中所有I/O操作都是非同步的,使用ChannelFuture可以獲取操作完成的結果,其 addListener()方法註冊了一個 ChannelFutureListener,以便在某個操作完成時(無論是否成功)得到通知。

ByteBuf

ByteBuf是Netty中的位元組緩衝區,相比於Java NIO中的 ByeBuffer,ByteBuf做了很多改進,ByteBuf的功能性和靈活性更好。

BootStrap

Netty提供的啟動輔助類,幫助Netty客戶端或服務端的Netty初始化,服務端對應的是 ServerBootStrap引導類。

小結

上面簡單的介紹了Netty的一些基本元件,後續文章會詳細對每個元件進行分析

參考資料 & 鳴謝

相關文章