Netty 权威指南笔记(六):Channel 解读

Netty 权威指南笔记(六):Channel 解读

《Netty 权威指南》书上使用的源码是 Netty5 的,但是 Netty5 已经被废弃了,所以本文是参照 Netty4.1 的源码解读的。

JDK 的 NIO 类库中,提供了 SocketChannel 和 ServerSocketChannel 用于非阻塞 I/O 操作。类似于 NIO 的 Channel,Netty 提供了自己的 Channel 和其子类实现。

功能说明

io.netty.channel.Channel 是 Netty 的网络操作抽象类,聚合了一组功能,包括但不限于网络读写、客户端发起连接、主动关闭连接,同时也包含了 Netty 框架相关的一些功能,包括获取 Channel 的 EventLoop,获取缓冲区分配器 ByteBufAllocator 和 pipeline 等。

为了 Netty 不使用 NIO 的原生 Channel,而是要另起炉灶呢?主要原因如下:
1. JDK 的 SocketChannel 和 ServerSocketChannel 没有统一的 Channel 接口供业务开发者使用。对用户而言,没有统一的操作视图,使用起来不方便。
2. JDK 的 SocketChannel 和 ServerSocketChannel 是 SPI 类接口,通过继承来扩展很不方便,不如开发一个新的。
3. Netty 的 Channel 需要能跟 Netty 架构融合在一起。
4. 自定义 Channel 功能实现会更灵活。

基于以上原因,Netty 重新设计了 Channel,其主要设计理念如下:
1. 在 Channel 接口层,采用 Facade 模式统一封装,将网络 I/O 操作、网络 I/O 相关联的其他操作封装起来,统一对外提供。
2. Channel 接口定义尽量大而全,为 SocketChannel 和 ServerSocketChannel 提供统一的视图,由不同子类实现不同的功能,公共功能在抽象父类中实现,最大程度上实现功能和接口的重用。
3. 具体实现采用聚合而非包含的方式,Channel 负责统一分配和调度,更加灵活。

Netty 的 Channel 都有哪些功能呢?
1. 常见的网络 IO 操作:读、写、绑定端口、连接、关闭连接等。
2. 获取 EventLoop。
3. 获取 parent Channel,对于服务端 SocketChannel 来说,parent 就是创建它的 ServerSocketChannel。
4. 唯一标志 id。
5. 元数据 metadata,获取 TCP 参数配置等。

源码分析

继承关系类图

Netty4 Channel 类图

NioServerSocketChannel、NioSocketChannel 两者都继承了 Channel、AbstractChannel、AbstractNioChannel。

AbstractChannel

主要成员变量如下所示:
1. 父 Channel。
2. 全局唯一 id。
3. Unsafe 实例。
4. 当前 Channel 对应的 DefaultChannelPipeline。
5. EventLoop。
6. 本地和远程地址。

    private final Channel parent;
    private final ChannelId id;
    private final Unsafe unsafe;
    private final DefaultChannelPipeline pipeline;
    private final VoidChannelPromise unsafeVoidPromise = new VoidChannelPromise(this, false);
    private final CloseFuture closeFuture = new CloseFuture(this);

    private volatile SocketAddress localAddress;
    private volatile SocketAddress remoteAddress;
    private volatile EventLoop eventLoop;
    private volatile boolean registered;
    private boolean closeInitiated;

    /** Cache for the string representation of this channel */
    private boolean strValActive;
    private String strVal;

AbstractChannel 中的网络 I/O 操作都是调用 pipeline 中的对应方法,继而由 pipeline 调用 ChannelHandler 进行处理。

    @Override
    public ChannelFuture bind(SocketAddress localAddress) {
        return pipeline.bind(localAddress);
    }

    @Override
    public ChannelFuture connect(SocketAddress remoteAddress) {
        return pipeline.connect(remoteAddress);
    }

    @Override
    public ChannelFuture write(Object msg) {
        return pipeline.write(msg);
    }

AbstractNioChannel

主要成员变量有:
1. SelectableChannel:这是一个 Java NIO SocketChannel 和 ServerSocketChannel 的公共父类,放在这里是因为 AbstractNioChannel 也是 NioSocketChannel 和 NioServerSocketChannel 的公共父类。
2. readInterestOp:代表 JDK SelectionKey 的 OP_READ。
3. SelectionKey:Channel 注册到 EventLoop(Selector)时返回的 key,修改它可以改变感兴趣的事件。
4. connectPromise:代表连接操作结果。
5. connectTimeoutFuture:连接超时定时器。
6. requestedRemoteAddress:connect 时的远程地址。

    private final SelectableChannel ch;
    protected final int readInterestOp;
    volatile SelectionKey selectionKey;
    boolean readPending;

    /**
     * The future of the current connection attempt.  If not null, subsequent
     * connection attempts will fail.
     */
    private ChannelPromise connectPromise;
    private ScheduledFuture<?> connectTimeoutFuture;
    private SocketAddress requestedRemoteAddress;

AbstractNioChannel 类里比较重要的方法是 doRegister,该方法负责将 Channel 注册到多路复用器 Selector。

    @Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
                selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
                return;
            } catch
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值