# 精尽 Netty 源码解析 —— Channel(一)之简介 # 1. 概述 在前面的文章中,我们已经不断看到 Netty Channel 的身影,例如: - 在 [《精尽 Netty 源码分析 —— 启动(一)之服务端》](http://svip.iocoder.cn/Netty/bootstrap-1-server/) 中,我们看了服务端 NioServerSocketChannel **对象创建**的过程。 - 在 [《精尽 Netty 源码分析 —— 启动(二)之客户端》](http://svip.iocoder.cn/Netty/bootstrap-2-client/) 中,我们看了客户端 NioSocketChannel **对象创建**的过程。 但是,考虑到本小节的后续文章,我们还是需要这样一篇文章,整体性的再看一次 Channel 的面貌。 # 2. Channel `io.netty.channel.Channel` ,实现 AttributeMap、ChannelOutboundInvoker、Comparable 接口,Netty Channel 接口。 在 [《精尽 Netty 源码分析 —— Netty 简介(一)之项目结构》](http://svip.iocoder.cn/Netty/intro-1/) 中,我们对 Channel 的组件定义如下: > Channel 是 Netty 网络操作抽象类,它除了包括基本的 I/O 操作,如 bind、connect、read、write 之外,还包括了 Netty 框架相关的一些功能,如获取该 Channel 的 EventLoop 。 > > 在传统的网络编程中,作为核心类的 Socket ,它对程序员来说并不是那么友好,直接使用其成本还是稍微高了点。而 Netty 的 Channel 则提供的一系列的 API ,它大大降低了直接与 Socket 进行操作的复杂性。而相对于原生 NIO 的 Channel,Netty 的 Channel 具有如下优势( 摘自《Netty权威指南( 第二版 )》) : > > - 在 Channel 接口层,采用 Facade 模式进行统一封装,将网络 I/O 操作、网络 I/O 相关联的其他操作封装起来,统一对外提供。 > - Channel 接口的定义尽量大而全,为 SocketChannel 和 ServerSocketChannel 提供统一的视图,由不同子类实现不同的功能,公共功能在抽象父类中实现,最大程度地实现功能和接口的重用。 > - 具体实现采用聚合而非包含的方式,将相关的功能类聚合在 Channel 中,由 Channel 统一负责和调度,功能实现更加灵活。 ## 2.1 基础查询 ``` /** * Returns the globally unique identifier of this {@link Channel}. * * Channel 的编号 */ ChannelId id(); /** * Return the {@link EventLoop} this {@link Channel} was registered to. * * Channel 注册到的 EventLoop */ EventLoop eventLoop(); /** * Returns the parent of this channel. * * 父 Channel 对象 * * @return the parent channel. * {@code null} if this channel does not have a parent channel. */ Channel parent(); /** * Returns the configuration of this channel. * * Channel 配置参数 */ ChannelConfig config(); /** * Returns an internal-use-only object that provides unsafe operations. * * Unsafe 对象 */ Unsafe unsafe(); /** * Return the assigned {@link ChannelPipeline}. * * ChannelPipeline 对象,用于处理 Inbound 和 Outbound 事件的处理 */ ChannelPipeline pipeline(); /** * Return the assigned {@link ByteBufAllocator} which will be used to allocate {@link ByteBuf}s. * * ByteBuf 分配器 */ ByteBufAllocator alloc(); /** * Returns the local address where this channel is bound to. The returned * {@link SocketAddress} is supposed to be down-cast into more concrete * type such as {@link InetSocketAddress} to retrieve the detailed * information. * * 本地地址 * * @return the local address of this channel. * {@code null} if this channel is not bound. */ SocketAddress localAddress(); /** * Returns the remote address where this channel is connected to. The * returned {@link SocketAddress} is supposed to be down-cast into more * concrete type such as {@link InetSocketAddress} to retrieve the detailed * information. * * 远端地址 * * @return the remote address of this channel. * {@code null} if this channel is not connected. * If this channel is not connected but it can receive messages * from arbitrary remote addresses (e.g. {@link DatagramChannel}, * use {@link DatagramPacket#recipient()} to determine * the origination of the received message as this method will * return {@code null}. */ SocketAddress remoteAddress(); ``` - 自身基本信息有 `#id()`、`#parent()`、`#config()`、`#localAddress()`、`#remoteAddress()` 方法。 - 每个 Channel 都有的核心组件有 `#eventLoop()`、`#unsafe()`、`#pipeline()`、`#alloc()` 方法。 ## 2.2 状态查询 ``` /** * Returns {@code true} if the {@link Channel} is open and may get active later * * Channel 是否打开。 * * true 表示 Channel 可用 * false 表示 Channel 已关闭,不可用 */ boolean isOpen(); /** * Returns {@code true} if the {@link Channel} is registered with an {@link EventLoop}. * * Channel 是否注册 * * true 表示 Channel 已注册到 EventLoop 上 * false 表示 Channel 未注册到 EventLoop 上 */ boolean isRegistered(); /** * Return {@code true} if the {@link Channel} is active and so connected. * * Channel 是否激活 * * 对于服务端 ServerSocketChannel ,true 表示 Channel 已经绑定到端口上,可提供服务 * 对于客户端 SocketChannel ,true 表示 Channel 连接到远程服务器 */ boolean isActive(); /** * Returns {@code true} if and only if the I/O thread will perform the * requested write operation immediately. Any write requests made when * this method returns {@code false} are queued until the I/O thread is * ready to process the queued write requests. * * Channel 是否可写 * * 当 Channel 的写缓存区 outbound 非 null 且可写时,返回 true */ boolean isWritable(); /** * 获得距离不可写还有多少字节数 * * Get how many bytes can be written until {@link #isWritable()} returns {@code false}. * This quantity will always be non-negative. If {@link #isWritable()} is {@code false} then 0. */ long bytesBeforeUnwritable(); /** * 获得距离可写还要多少字节数 * * Get how many bytes must be drained from underlying buffers until {@link #isWritable()} returns {@code true}. * This quantity will always be non-negative. If {@link #isWritable()} is {@code true} then 0. */ long bytesBeforeWritable(); ``` 一个**正常结束**的 Channel 状态转移有**两**种情况: - 服务端用于绑定( bind )的 Channel 、或者客户端发起连接( connect )的 Channel 。 ``` REGISTERED -> CONNECT/BIND -> ACTIVE -> CLOSE -> INACTIVE -> UNREGISTERED ``` - 服务端接受( accept )客户端的 Channel 。 ``` REGISTERED -> ACTIVE -> CLOSE -> INACTIVE -> UNREGISTERED ``` 一个**异常关闭**的 Channel 状态转移不符合上面的。 ## 2.3 IO 操作 ``` @Override Channel read(); @Override Channel flush(); ``` - 这两个方法,继承自 ChannelOutboundInvoker 接口。实际还有如下几个: ``` ChannelFuture bind(SocketAddress localAddress); ChannelFuture connect(SocketAddress remoteAddress); ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress); ChannelFuture disconnect(); ChannelFuture close(); ChannelFuture deregister(); ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise); ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise); ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise); ChannelFuture disconnect(ChannelPromise promise); ChannelFuture close(ChannelPromise promise); ChannelFuture deregister(ChannelPromise promise); ChannelOutboundInvoker read(); ChannelFuture write(Object msg); ChannelFuture write(Object msg, ChannelPromise promise); ChannelOutboundInvoker flush(); ChannelFuture writeAndFlush(Object msg, ChannelPromise promise); ChannelFuture writeAndFlush(Object msg); ``` - 对比下来,我们会发现 Channel 重写 ChannelOutboundInvoker 这两个接口的原因是:将返回值从 ChannelOutboundInvoker 修改成 Channel 。 - 我们看到除了 `#read()` 和 `#flush()` 方法,其它方法的返回值的类型都是 ChannelFuture ,这表明这些操作是**异步** IO 的过程。 ## 2.4 异步结果 Future ``` /** * Returns the {@link ChannelFuture} which will be notified when this * channel is closed. This method always returns the same future instance. * * Channel 关闭的 Future 对象 */ ChannelFuture closeFuture(); ``` - 除了自定义的 `#closeFuture()` 方法,也从 ChannelOutboundInvoker 接口继承了几个接口方法: ``` ChannelPromise newPromise(); ChannelProgressivePromise newProgressivePromise(); ChannelFuture newSucceededFuture(); ChannelFuture newFailedFuture(Throwable cause); ChannelPromise voidPromise(); ``` - 通过这些接口方法,可创建或获得和该 Channel 相关的 Future / Promise 对象。 ## 2.5 类图 Channel 的子接口和实现类如下图: [](http://static.iocoder.cn/images/Netty/2018_07_01/01.png)Channel 的子接口和实现类 - 本图包含了 NIO、OIO、Local、Embedded 四种 Channel 实现类。说明如下:[](http://static.iocoder.cn/images/Netty/2018_07_01/02.png)Channel 四种 Channel 实现类的说明 - 本系列仅分享 NIO 部分,所以裁剪类图如下:[之简介.assets/03.png)](http://static.iocoder.cn/images/Netty/2018_07_01/03.png)NIO Channel 类图 # 3. Unsafe Unsafe **接口**,定义在在 `io.netty.channel.Channel` 内部,和 Channel 的操作**紧密结合**,下文我们将看到。 Unsafe 直译中文为“不安全”,就是告诉我们,**无需**且**不必要**在我们使用 Netty 的代码中,**不能直接**调用 Unsafe 相关的方法。Netty 注释说明如下: ``` /** * Unsafe operations that should never be called from user-code. * * These methods are only provided to implement the actual transport, and must be invoked from an I/O thread except for the * following methods: *