天天看點

Netty源碼剖析與實戰-第四周第三章:Netty 源碼 從“線”(請求處理)的角度剖析

第三章:Netty 源碼 從“線”(請求處理)的角度剖析

目錄

第三章:Netty 源碼 從“線”(請求處理)的角度剖析

Netty 代碼編譯與總覽

編譯Netty 常遇問題

Netty 源碼核心包速覽

啟動服務

主線

知識點

建構連接配接

主線

知識點

接受資料

讀資料技巧

主線

Netty 代碼編譯與總覽

編譯Netty 常遇問題

常見問題一:maven 插件會根據System.getProperties的内容生成對應依賴,如果是window32位無對應依賴

Netty源碼剖析與實戰-第四周第三章:Netty 源碼 從“線”(請求處理)的角度剖析

常見問題二:需先将netty-common包進行編譯

Netty源碼剖析與實戰-第四周第三章:Netty 源碼 從“線”(請求處理)的角度剖析

Netty 源碼核心包速覽

Netty源碼剖析與實戰-第四周第三章:Netty 源碼 從“線”(請求處理)的角度剖析

啟動服務

主線

Netty源碼剖析與實戰-第四周第三章:Netty 源碼 從“線”(請求處理)的角度剖析

知識點

啟動服務的本質:

Selector selector = sun.nio.ch.SelectorProviderImpl.openSelector()  

ServerSocketChannel serverSocketChannel = provider.openServerSocketChannel() 

selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);

javaChannel().bind(localAddress, config.getBacklog());

selectionKey.interestOps(OP_ACCEPT);

Selector 是在new NioEventLoopGroup()(建立一批NioEventLoop)時建立。

第一次Register 并不是監聽OP_ACCEPT,而是0:

selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this) 。

最終監聽OP_ACCEPT 是通過bind 完成後的fireChannelActive() 來觸發的。

NioEventLoop 是通過Register 操作的執行來完成啟動的。

類似ChannelInitializer,一些Hander 可以設計成一次性的,用完就移除,例如授權。

建構連接配接

主線

Netty源碼剖析與實戰-第四周第三章:Netty 源碼 從“線”(請求處理)的角度剖析

知識點

接受連接配接本質:

selector.select()/selectNow()/select(timeoutMillis) 發現OP_ACCEPT 事件,處理:

SocketChannel socketChannel = serverSocketChannel.accept()

selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);

selectionKey.interestOps(OP_READ);

建立連接配接的初始化和注冊是通過pipeline.fireChannelRead 在ServerBootstrapAcceptor 中完成的。

第一次Register 并不是監聽OP_READ ,而是0 :

selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this) 。

最終監聽OP_READ 是通過“Register”完成後的fireChannelActive

(io.netty.channel.AbstractChannel.AbstractUnsafe#register0中)來觸發的

Worker’s NioEventLoop 是通過Register 操作執行來啟動。

接受連接配接的讀操作,不會嘗試讀取更多次(16次)。

接受資料

讀資料技巧

1 自适應資料大小的配置設定器(AdaptiveRecvByteBufAllocator):

發放東西時,拿多大的桶去裝?小了不夠,大了浪費,是以會自己根據實際裝的情況猜一猜下次情況,

進而決定下次帶多大的桶。

2 連續讀(defaultMaxMessagesPerRead):

發放東西時,假設拿的桶裝滿了,這個時候,你會覺得可能還有東西發放,是以直接拿個新桶等着裝,

而不是回家,直到後面出現沒有裝上的情況或者裝了很多次需要給别人一點機會等原因才停止,回家。

主線

• 多路複用器( Selector )接收到OP_READ 事件

• 處理OP_READ 事件:NioSocketChannel.NioSocketChannelUnsafe.read()

• 配置設定一個初始1024 位元組的byte buffer 來接受資料

• 從Channel 接受資料到byte buffer

• 記錄實際接受資料大小,調整下次配置設定byte buffer 大小

• 觸發pipeline.fireChannelRead(byteBuf) 把讀取到的資料傳播出去

• 判斷接受byte buffer 是否滿載而歸:是,嘗試繼續讀取直到沒有資料或滿16 次;

否,結束本輪讀取,等待下次OP_READ 事件

worker thread

備注:本文皆轉自極客時間-netty源碼剖析與實戰,本人僅作整理和部分解讀,用于記錄和記憶留存!