Channel 概述简介
在Netty中,Channel相当于Socket的抽象,给用户提供了Socket的状态、Socket的读写等操作使用。每当建立一个连接,都创建一个连接对应的Channel 实例;
不同的连接类型,对应的Channel类型也不同
Channel类型 | 说明 |
---|---|
NioSocketChannel | 异步非阻塞的TCP客户端连接 |
NioServerSocketChannel | 异步非阻塞的TCP服务端连接 |
NioDatagramChannel | 异步非阻塞UDP连接 |
NioSctpChannel | 异步的SCTP连接 |
NioSctpServerChannel | 异步的SCTP服务端连接 |
Oio … | 同步阻塞连接 |
Channel 初始化
在BootStrap初始化时,调用channel()方法传入NioSocketChannel.class,在channel()方法中创建了ReflectiveChannelFactory对象,如下:
public B channel(Class <? extends C> channelClass){
if(channelClass == null){
throw new NullPointerException("channelClass");
}
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
ReflectiveChannelFactory实现了ChannelFactory 接口,提供了唯一的方法 newChannel()方法,作用的创建Channel的工厂类。
Channel的注册
- AbstractBootStrap的initAndRegister()方法,触发启动Channel注册
- MultitheradEventLoopGroup的register()中,调用next()方法, 从内部数组中取出一个可用的EventLoop,即对应线程,跟Channel形成关联
- AbstractUnSafe的register0()方法中,将底层的JDK的NioSocketChannel注册至Selector上
Channel的生命周期
ChannelPipeLine
在创建Channel时,同时创建与其对应的ChannelPipeLine,ChannelPipeLine内部维护一个双向链表,链表的元素为ChannelHandlerContext;因此它拥有两个属性,head和tail
ChannelPipeLine的创建
(1) 在AbstractChannel的构造函数中,调用newChannelPipeLine();
(2) DefaultChannelPipeLine的构造函数中,初始化两个DefaultChannelHandlerContext的元素,分别为head和tail
(3) 在BootStrap启动时,会传入1个ChannelInitializer,在init方法中,会将这个ChannelInitializer转换为ChannelHandlerContext对象,插入ChannelPipeLine的链表中,会判断这个Handler是属于InBound还是OutBound,ChannelInitializer是一个固定为InBound的ChannelHandler
插入自定义ChannelHandler
在ChannelPipeLine创建后,它有1个head、tail、ChannelInitializer的Context,3个元素;
(1) 遍历ChannelPipeLine,找到InBound属性为True的Context,这里找到的就是ChannelInitializer的Context;
(2) 调用 context的invokeChannelRegistered方法,内部调用initChannel方法将ChannelHandler包装为ChannelContextHandler对象,插入ChannelPipeLine中;
(4) 删除ChannelPipeLine中的原来的ChannelInitializer的Context
ChannelPipeLine的事件传播机制
事件类型
Netty里事件类型分为两种,InBound事件和OutBound事件;
InBound事件是被动触发的事件,有channelRead、Active、exception等,InBound事件从Head到Tail传播;
OutBound事件是主动触发的事件,有connect、disconnct、write、flush等,OutBound时间从Tail到Head传播;
对应处理Inbound事件的就是ChannelInBoundHandler,处理OutBound事件的就是ChannelOutBoundHandler;
OutBound事件传播流程
(1) 从Tail节点开始,寻找下一个自定义的ChannelOutBoundHandler,找到则调用其对应方法,比如connect();
(2) 继续寻找下一个自定义的ChannelOutBoundHandler,找到则调用其对应方法,比如connect();
(3) 直到找到Head,Head本身即是ChannelHandlerContext也是ChannelOutBoundHandler,调用其connect()方法
(4) Head的connect方法内部调用了UnSafe的connect方法,进入底层的TCP连接动作
InBound事件传播流程
(1) 从Head节点开始,寻找下一个自定义的ChannelInBoundHandler,找到则调用其对应方法,比如channelActive();
(2) 继续寻找下一个自定义的ChannelInBoundHandler,找到则调用其对应方法,比如channelActive();
(3) 直到找到Tail,Tail本身即是ChannelHandlerContext也是ChannelInBoundHandler,调用其channelActive()方法
(4) 发现Tail的ChannelActive()方法没有任何实现,这是因为Tail的所有InBound方法都是默认不实现的