Netty系列之源碼解析(一)

Netty源碼解析(一):開始

當前:Netty 源碼解析(二): Netty 的 Channel

Netty 源碼解析(三): Netty?的 Future 和 Promise

Netty 源碼解析(四): Netty 的 ChannelPipeline

Netty 源碼解析(五): Netty 的線程池分析

Netty 源碼解析(六): Channel 的 register 操作

Netty 源碼解析(七): NioEventLoop 工作流程

Netty 源碼解析(八): 回到 Channel 的 register 操作

Netty 源碼解析(九): connect 過程和 bind 過程分析

今天呢!燈塔君跟大家講:??

Netty 的 Channel

這節(jié)我們來看看 NioSocketChannel 是怎么和 JDK 底層的 SocketChannel 聯(lián)系在一起的,它們是一對一的關系。NioServerSocketChannel 和 ServerSocketChannel 同理,也是一對一的關系。

在 Bootstrap(客戶端) 和 ServerBootstrap(服務端) 的啟動過程中都會調用 channel(…) 方法:

下面,我們來看 channel(…) 方法的源碼:

1//?AbstractBootstrap

2public?B?channel(Class<??extends?C>?channelClass)?{

3????if?(channelClass?==?null)?{

4????????throw?new?NullPointerException("channelClass");

5????}

6????return?channelFactory(new?ReflectiveChannelFactory<C>(channelClass));

7}

我們可以看到,這個方法只是設置了 channelFactory 為 ReflectiveChannelFactory 的一個實例,然后我們看下這里的 ReflectiveChannelFactory 到底是什么:

newChannel()方法是 ChannelFactory 接口中的唯一方法,工廠模式大家都很熟悉。我們可以看到,ReflectiveChannelFactory#newChannel() 方法中使用了反射調用 Channel 的無參構造方法來創(chuàng)建 Channel,我們只要知道,ChannelFactory 的 newChannel() 方法什么時候會被調用就可以了。

對于NioSocketChannel,由于它充當客戶端的功能,它的創(chuàng)建時機在 connect(…) 的時候;

對于NioServerSocketChannel來說,它充當服務端功能,它的創(chuàng)建時機在綁定端口bind(…)的時候。

接下來,我們來簡單追蹤下充當客戶端的Bootstrap中NioSocketChannel的創(chuàng)建過程,看看NioSocketChannel是怎么和JDK 中的SocketChannel關聯(lián)在一起的:

1//?Bootstrap

2public?ChannelFuture?connect(String?inetHost,?int?inetPort)?{

3????return?connect(InetSocketAddress.createUnresolved(inetHost,?inetPort));

4}

然后再往里看到這個方法:

1public?ChannelFuture?connect(SocketAddress?remoteAddress)?{

2????if?(remoteAddress?==?null)?{

3????????throw?new?NullPointerException("remoteAddress");

4????//?validate?只是校驗一下各個參數(shù)是不是正確設置了

5????validate();

6????return?doResolveAndConnect(remoteAddress,?config.localAddress());

7}

繼續(xù):

1//?再往里就到這里了2private?ChannelFuture?doResolveAndConnect(final?SocketAddress?remoteAddress,?final?SocketAddress?localAddress)?{

3????//?我們要說的部分在這里

4????final?ChannelFuture?regFuture?=?initAndRegister();

5????final?Channel?channel?=?regFuture.channel();

6????......

7}

然后,我們看initAndRegister()方法:

1final?ChannelFuture?initAndRegister()?{

2????Channel?channel?=?null;

3????try?{

4????????//?前面我們說過,這里會進行?Channel?的實例化

5????????channel?=?channelFactory.newChannel();

6????????init(channel);

7????}?catch?(Throwable?t)?{

8????????...

9????}

10????...

11????return?regFuture;

12}

我們找到了channel = channelFactory.newChannel()這行代碼,根據(jù)前面說的,這里會調用相應Channel的無參構造方法。

然后我們就可以去看NioSocketChannel的構造方法了:

1public?NioSocketChannel()?{

2????//?SelectorProvider?實例用于創(chuàng)建?JDK?的?SocketChannel?實例

3????this(DEFAULT_SELECTOR_PROVIDER);

4}

5

6public?NioSocketChannel(SelectorProvider?provider)?{

7????//?看這里,newSocket(provider)?方法會創(chuàng)建?JDK?的?SocketChannel

8????this(newSocket(provider));

9}

我們可以看到,在調用 newSocket(provider) 的時候,會創(chuàng)建JDK NIO的一個 SocketChannel實例:

1private?static?SocketChannel?newSocket(SelectorProvider?provider)?{

2????try?{

3????????//?創(chuàng)建?SocketChannel?實例

4????????return?provider.openSocketChannel();

5????}?catch?(IOException?e)?{

6????????throw?new?ChannelException("Failed?to?open?a?socket.",?e);

7????}

8}

NioServerSocketChannel同理,也非常簡單,從ServerBootstrap#bind(...)方法一路點進去就清楚了。

所以我們知道了,NioSocketChannel 在實例化過程中,會先實例化JDK底層的 SocketChannel,NioServerSocketChannel 也一樣,會先實例化 ServerSocketChannel 實例:

說到這里,我們順便再繼續(xù)往里看一下NioSocketChannel的構造方法:

1public?NioSocketChannel(SelectorProvider?provider)?{

2????this(newSocket(provider));

3}

剛才我們看到這里newSocket(provider)創(chuàng)建了底層的SocketChannel 實例我們繼續(xù)往下看構造方法:

1public?NioSocketChannel(Channel?parent,?SocketChannel?socket)?{

2????super(parent,?socket);

3????config?=?new?NioSocketChannelConfig(this,?socket.socket());

4}

上面有兩行代碼,第二行代碼很簡單,實例化了內部的 NioSocketChannelConfig 實例,它用于保存channel的配置信息,這里沒有我們現(xiàn)在需要關心的內容,直接跳過。

第一行調用父類構造器,除了設置屬性外,還設置了SocketChannel的非阻塞模式:

1protected?AbstractNioByteChannel(Channel?parent,?SelectableChannel?ch)?{

2????//?毫無疑問,客戶端關心的是?OP_READ?事件,等待讀取服務端返回數(shù)據(jù)

3????super(parent,?ch,?SelectionKey.OP_READ);

4}

5

6//?然后是到這里

7protected?AbstractNioChannel(Channel?parent,?SelectableChannel?ch,?int?readInterestOp)?{

8????super(parent);

9????this.ch?=?ch;

10????//?我們看到這里只是保存了?SelectionKey.OP_READ?這個信息,在后面的時候會用到

11????this.readInterestOp?=?readInterestOp;

12????try?{

13????????//?******設置?channel?的非阻塞模式******

14????????ch.configureBlocking(false);

15????}?catch?(IOException?e)?{

16????????......

17????}

18}

NioServerSocketChannel的構造方法類似,也設置了非阻塞,然后設置服務端關心的SelectionKey.OP_ACCEPT事件:

1public?NioServerSocketChannel(ServerSocketChannel?channel)?{

2????//?對于服務端來說,關心的是?SelectionKey.OP_ACCEPT?事件,等待客戶端連接

3????super(null,?channel,?SelectionKey.OP_ACCEPT);

4????config?=?new?NioServerSocketChannelConfig(this,?javaChannel().socket());

5}

這節(jié)關于Channel的內容我們先介紹這么多,主要就是實例化了JDK層的SocketChannel或ServerSocketChannel,然后設置了非阻塞模式,我們后面再繼續(xù)深入下去。

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容