-
Channel:Java Stream是以流的方式一個一個byte通過滑動窗口來接收,是連續性的,造成阻塞,只能一次性接收完。而NIO Channel非阻塞,但是必須通過Buffer來中轉。
-
Buffer:可理解爲一個數組的封裝,例如 IntBuffer、CharBuffer、ByteBuffer 等分別對應 int[]、char[]、byte[] 等。有Byte/Short/Long/Int/Float/Double/Char/MappedByteBuffer。
-
buffer四個基本屬性:
-
capacity:當前buffer的最大容量,如int[] buffer = new int[1024]; 那capacity=1024
-
position:當前buffer真實已用的下一個位置,如buffer最大容量=1024,現在真實用了500,那position=500
-
limit:讀情況下,limit=buffer實際大小;寫情況下,limit=capacity
-
mark:記錄當前postion位置,即標記上一次讀寫位置
-
-
mark <= position <= limit <= capacity
-
-
Selector:輪詢channel,輪詢到某個channel是讀寫時間的就緒狀態,就取出來
Netty源碼簡析之服務端Channel的創建
1 引入netty的maven依賴如下
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>
2 netty的基本組件如下
netty啓動過程分爲:
- 創建服務端channel
- 初始化服務端channel
- 註冊selector
3 以下是一個簡單的netty服務段程序代碼(在後續部分講解會用到)
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // A點 設置channel
.childOption(ChannelOption.TCP_NODELAY, true)
.childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")
.handler(new ServerHandler())
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new AuthHandler());
}
});
ChannelFuture f = b.bind(8888).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
4 服務端Channel的創建過程
/** AbstractBootStrap.java類中
* Create a new {@link Channel} and bind it.
*/
public ChannelFuture bind(int inetPort) {
return bind(new InetSocketAddress(inetPort));
}
/** AbstractBootStrap.java類中
* Create a new {@link Channel} and bind it.
*/
public ChannelFuture bind(SocketAddress localAddress) {
validate();
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
return doBind(localAddress);
}
然後調用initAndRegister()創建服務端channel
// AbstractBootStrap.java類中
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
...........
}
最終發現是通過newChannel()創建的,點進去發現是由clazz.newInstance()反射來創建一個channel
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
...................
}
閱讀上面的代碼可知channel是通過反射來創建的,但是對應的對象channelFactory是如何初始化的?
首先我們看3的A點,可以看到通過.chanel(NioServerSocketChannel.class)設置了channelFactory,往下繼續跟
點擊.channel()方法後進入查看如下
public B channel(Class<? extends C> channelClass) {
...........
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
上面可知 NioServerSocketChannel.class 傳入ReflectiveChannelFactory中,然後賦值給了裏面的一個clazz參數。然後最後包裝好會賦值給AbstractBootStrap.java的channelFactory屬性,最終複製代碼如下
public B channelFactory(ChannelFactory<? extends C> channelFactory) {
if (channelFactory == null) {
throw new NullPointerException("channelFactory");
}
if (this.channelFactory != null) {
throw new IllegalStateException("channelFactory set already");
}
this.channelFactory = channelFactory;
return (B) this;
}
總結:通過channel(NioServerSocketChannel.class),傳入NioServerSocketChannel.class,然後使用ReflectiveChannelFactory包裝後賦值給channelFactory屬性。然後最終調用clazz.newInstance()來實例化一個channel實例。
通過上面我們可以知道channel是通過反射來創建的,接下來我們來看看他創建對應的NioServerSocketChannel.java類,其構造方法如下:
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
首先點擊newSocket()方法如下,可見調用的jdk底層來創建socket(點擊openServerSocketChannel() 可見其在jdk1.8的包中)
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException("Failed to open a server socket.", e);
}
}
然後繼續點擊this(newSocket(DEFAULT_SELECTOR_PROVIDER))的this,找到當前對應的方法如下:
public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
點擊super()層層往上看,最後找到代碼如下:
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
ch.configureBlocking(false); //設置非阻塞
.................
}
由上可見其默認設置了非阻塞(通過 ch.configureBlocking(false) 設置),繼續看上面的super(parent)方法如下:
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}
可看到其最終賦值了(id,unsafe,pipeline)這三個屬性,這幾個屬性將會在後續用到。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.