Netty源碼分析(一)概覽

準備將Netty的源碼過一下,一來對本身是個總結消化的過程,二來但願對那些打算看Netty源碼的人(已經熟悉Netty的Reactor模型)能有一些幫助。目前所看Netty版本是4.1.3.Final。tomcat

1 目錄

2 概覽

2.1 服務器端demo

看下一個簡單的Netty服務器端的例子安全

public static void main(String[] args){
	EventLoopGroup bossGroup=new NioEventLoopGroup(1);
	EventLoopGroup workerGroup = new NioEventLoopGroup();
	try {
		ServerBootstrap serverBootstrap=new ServerBootstrap();
		serverBootstrap.group(bossGroup,workerGroup)
			.channel(NioServerSocketChannel.class)
			.option(ChannelOption.SO_BACKLOG, 200)
			.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(80,0,4,0,4));
					ch.pipeline().addLast(new StringDecoder(Charset.forName("UTF-8")));
					ch.pipeline().addLast(new TcpServerHandler());
				}
			});
		ChannelFuture f=serverBootstrap.bind(8080).sync();
		f.channel().closeFuture().sync();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}finally {  
        workerGroup.shutdownGracefully();  
        bossGroup.shutdownGracefully();  
    }  
}

先來簡單說說上述遇到的類:服務器

2.2 EventLoopGroup介紹

它主要包含2個方面的功能,註冊Channel和執行一些Runnable任務。微信

EventLoopGroup介紹

功能1:先來看看註冊Channel,即將Channel註冊到Selector上,由Selector來調度Channel的相關事件,如讀、寫、Accept等事件。多線程

而EventLoopGroup的設計是,它包含多個EventLoop(每個EventLoop一般內部包含一個線程),在執行上述註冊過程當中是須要選擇其中的一個EventLoop來執行上述註冊行爲,這裏就出現了一個選擇策略的問題,該選擇策略接口是EventExecutorChooser,你也能夠自定義一個實現。併發

從上面能夠看到,EventLoopGroup作的工做大部分是一些整體性的工做如初始化上述多個EventLoop、EventExecutorChooser等,具體的註冊Channel仍是交給它內部的EventLoop來實現。異步

功能2:執行一些Runnable任務ide

EventLoopGroup繼承了EventExecutorGroup,EventExecutorGroup也是EventExecutor的集合,EventExecutorGroup也是掌管着EventExecutor的初始化工做,EventExecutorGroup對於Runnable任務的執行也是選擇內部中的一個EventExecutor來作具體的執行工做。oop

netty中不少任務都是異步執行的,一旦當前線程要對某個EventLoop執行相關操做,如註冊Channel到某個EventLoop,若是當前線程和所要操做的EventLoop內部的線程不是同一個,則當前線程就僅僅向EventLoop提交一個註冊任務,對外返回一個ChannelFuture。.net

總結:EventLoopGroup含有上述2種功能,它更多的是一個集合,可是具體的功能實現仍是選擇內部的一個item元素來執行相關任務。 這裏的內部item元素一般即實現了EventLoop,又實現了EventExecutor,如NioEventLoop等

2.3 ChannelPipeline介紹

上述EventLoopGroup能夠將一個Channel註冊到內部的一個EventLoop的Selector上,而後對於這個Channel的相關讀寫等事件,Netty專門設計了一個ChannelPipeline來進行處理。每個Channel都有一個ChannelPipeline來處理該Channel的讀寫等事件。

ChannelPipeline介紹

2.4 bind過程

上述serverBootstrap的bind過程以下:

  • 建立出你所指定的NioServerSocketChannel,而後初始化一些Socket方面的參數

  • 爲上述Channel的ChannelPipeline配置一個ChannelHandler,該ChannelHandler的做用就是在該Channel成功註冊到Selector上的時候,初始化一些邏輯,即initChannel方法中執行一些邏輯,該邏輯就是向ChannelPipeline中添加一個新的ChannelHandler即ServerBootstrapAcceptor

  • 而後開始將該Channel註冊到上述EventLoopGroup bossGroup中,該EventLoopGroup bossGroup會選擇內部的一個EventLoop來執行實際的註冊行爲(這個時候就是當前線程和操做的EventLoop不是同一個線程,即該過程是異步提交一個Runnable),一旦註冊完成,就執行上述ChannelHandler的initChannel方法

至此,就完成了整個bind過程。一旦EventLoop內部的Selector檢測到NioServerSocketChannel有新的鏈接到來的事件,則會交給NioServerSocketChannel的ChannelPipeline來處理,重點就是ChannelPipeline中的上述ServerBootstrapAcceptor,ServerBootstrapAcceptor作以下操做:

  • 1 爲新的Channel的ChannelPipeline配置咱們上述代碼中的childHandler指定的ChannelHandler

  • 2 將新的Channel註冊到了上述EventLoopGroup workerGroup中

2.5 sync介紹

bind方法返回的是一個ChannelFuture,從上面咱們也知道該過程是異步的,sync方法則是一直等待到該異步過程結束。

再看下f.channel().closeFuture().sync()這個方法

每個ChannelFuture都是和一個Channel綁定的,因此能夠經過ChannelFuture來獲取對應綁定的Channel對象

每個Channel對象都有一個CloseFuture closeFuture對象,上述closeFuture方法並非去執行close方法而是獲取到這個CloseFuture closeFuture對象,而後調用它的sync方法即等待這個Future的結束。通常正常狀況下是不會調用這個Future的結束方法的,只是在上述過程或者其餘過程出現問題的時候,如註冊到EventLoop失敗等纔會去調用這個Feture的結束方法,因此正常狀況下主線程會一直阻塞在CloseFuture closeFuture的sync方法上。

3 誤區

上述的bossGroup的建立問題。

咱們都知道bossGroup是用來accept鏈接,而後將鏈接綁定到workerGroup中的,通常狀況下bossGroup設置線程數爲1便可(基本只能爲1),咱們同時知道Ractor模型中可使用多個Acceptor線程來執行accept操做,加快accept的速度。

若是你想加快accept的速度,想開啓多線程來accept,這時候想設置bossGroup的線程數爲多個的話,就大錯特錯了,是根本沒效果的。

結合上面的原理,只有在bind端口的時候纔會建立一個ServerSocketChannel,而後註冊到bossGroup內部的一個EventLoop中,仍然是單線程負責ServerSocketChannel的accept工做,而bossGroup中的多線程僅僅是爲bind多個端口服務的。

咱們來看下tomcat是如何容許多個Acceptor線程來執行accept操做的:

  • 1 建立了一個ServerSocketChannel serverSock,並bind到某個端口

  • 2 開啓多個Acceptor線程,每一個線程邏輯都是執行上述serverSock的accept方法

沒有使用Selector來執行accept操做,能夠多線程併發執行上述serverSock的accept方法。

一旦使用了Selector,基本上就至關於將ServerSocketChannel serverSock綁定到了Selector所在線程上了(Selector不是線程安全的,只能在一個線程中被調度執行)

4 後續

下一篇就要詳細描述下EventLoopGroup了。

歡迎關注微信公衆號:乒乓狂魔

微信公衆號

相關文章
相關標籤/搜索