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ù)深入下去。