回顾#
全文围绕下图,Netty-Channel的简化版架构体系图展开,从顶层Channel接口开始入手,往下递进,闲言少叙,直接开撸
概述: 从图中可以看到,从顶级接口Channel开始,在接口中定义了一套方法当作规范,紧接着的是来两个抽象的接口实现类,在这个抽象类中对接口中的方法,进行了部分实现,然后开始根据不同的功能分支,分成服务端的Channel和客户端的Channel
Channel的分类#
根据服务端和客户端,Channel可以分成两类(这两大类的分支见上图):
- 服务端:
NioServerSocketChannel
- 客户端:
NioSocketChannel
什么是Channel?#
channel是一个管道,用于连接字节缓冲区Buf和另一端的实体,这个实例可以是Socket,也可以是File, 在Nio网络编程模型中, 服务端和客户端进行IO数据交互(得到彼此推送的信息)的媒介就是Channel
Netty对Jdk原生的ServerSocketChannel
进行了封装和增强封装成了NioXXXChannel
, 相对于原生的JdkChannel, Netty的Channel增加了如下的组件
- id 标识唯一身份信息
- 可能存在的parent Channel
- 管道 pepiline
- 用于数据读写的unsafe内部类
- 关联上相伴终生的NioEventLoop
本篇博客,会追溯上图中的体系关系,找出NioXXXChannel
的相对于jdk原生channel在哪里添加的上面的新组件
源码开始-Channel#
现在来到上图的Channel
部分, 他是一个接口, netty用它规定了一个Channel
应该具有的功能,在它的文档对Channel的
是什么,以及对各个组件进行了描述
- 阐述了channel是什么,有啥用
Channel
通过ChannelPipeline
中的多个Handler
处理器,Channel
使用它处理IO数据Channel
中的所有Io操作都是异步的,一经调用就马上返回,于是Netty基于Jdk原生的Future
进行了封装,ChannelFuture
, 读写操作会返回这个对象,实现自动通知IO操作已完成Channel
是可以有parent的, 如下
// 创建客户端channel时,会把服务端的Channel设置成自己的parent // 于是就像下面: 服务端的channel = 客户端的channel.parent(); 服务的channel.parent()==null;
此外,Channel还定义了大量的抽象方法, 如下:
/** * todo 返回一个仅供内部使用的unsafe对象, Chanel上 IO数据的读写都是借助这个类完成的 */ Unsafe unsafe(); // 返回Channel的管道 ChannelPipeline pipeline(); ByteBufAllocator alloc(); @Override // todo 进入第一个实现 , 读取Channel中的 IO数据 Channel read(); // 返回Channel id ChannelId id(); // todo 返回channel所注册的 eventLoop EventLoop eventLoop(); // 返回当前Channel的父channel Channel parent(); // todo 描述了 关于channel的 一些列配置信息 ChannelConfig config(); // 检查channel是否开启 boolean isOpen(); // 检查channel是否注册 boolean isRegistered(); // todo 什么是active 他说的是channel状态, 什么状态呢? 当前channel 若和Selector正常的通信就说明 active boolean isActive(); // 返回channel的元数据 ChannelMetadata metadata(); // 服务器的ip地址 SocketAddress localAddress(); // remoteAddress 客户端的ip地址 SocketAddress remoteAddress(); ChannelFuture closeFuture(); boolean isWritable(); long bytesBeforeUnwritable(); long bytesBeforeWritable(); @Override Channel flush();
Channel重要的内部接口 unsafe
#
Netty中,真正帮助Channel完成IO读写操作的是它的内部类unsafe
, 源码如下, 很多重要的功能在这个接口中定义, 下面列举的常用的方法
interface Unsafe { // 把channel注册进EventLoop void register(EventLoop eventLoop, ChannelPromise promise); // todo 给channel绑定一个 adress, void bind(SocketAddress localAddress, ChannelPromise promise); // 把channel注册进Selector void deregister(ChannelPromise promise); // 从channel中读取IO数据 void beginRead(); // 往channe写入数据 void write(Object msg, ChannelPromise promise); ... ...