Netty源码-Channel讲解

Channel的讲解

  • 阅读前需思考的问题
  • Netty中的Channel是什么?
  • Channel是怎么创建的?
  • Channel的创建时机?
  • Netty中的Channel和JDK中的Channel什么关系?
  • 两者什么时候关联起来的,怎么关联的?

Channel是什么?

Channel是对socket连接的封装,可以理解成Channel就是socket连接;Netty中的Channel分为NioSocketChannel(客户端)和NioServerSocketChannel(服务端)两种。 我们知道Netty是基于Java Nio的,那么与Java中的SocketChannel什么关系呢?是一对一的关系。

NioSocketChannel          --------->     SocketChannel           (1:1)
NioServerSocketChannel    --------->     ServerSocketChannel     (1:1)

Channel如何实例化的?

image.png

上图是Netty官网的Echo Server示例,左边是client端代码,右边是server端代码。NioSocketChannel和和NioServerSocketChannel都赋值给channel(...)方法了。

点进ServerBootstrap的channel方法一看究竟:

## AbstractBootstrap类

public B channel(Class<? extends C> channelClass) {
    // 以channelClass为参数,创建了ReflectiveChannelFactory对象
    // 从名字上看,是通过反射技术创建channel实例的工厂
    return channelFactory(new ReflectiveChannelFactory<C>(
            ObjectUtil.checkNotNull(channelClass, "channelClass")
    ));
}

继续点进去:

## ReflectiveChannelFactory类

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
    // 构造函数成员变量:constructor
    private final Constructor<? extends T> constructor;

    public ReflectiveChannelFactory(Class<? extends T> clazz) {
        ObjectUtil.checkNotNull(clazz, "clazz");
        try {
            // 获取一个无参构造函数
            this.constructor = clazz.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
                    " does not have a public non-arg constructor", e);
        }
    }

    @Override
    public T newChannel() {
        try {
            // 通过无参构造函数,创建一个实例
            return constructor.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
        }
    }
    ......
}

到此我们知道,在 newChannel() 方法中利用 反射技术 创建Channel实例的,此类使用了我们非常熟悉的工厂设计模式

思考:我们知道ReflectiveChannelFactory是利用反射技术创建对象的,是不是可以创建任意对象?不是的,泛型T是有约束条件的,T 必须是实现Channel接口的类才行的。

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> 
## 泛型T是有约束条件的,T 必须是实现Channel接口的类

Channel无参构造函数做了什么?

来看下NioServerSocketChannel类:

## NioServerSocketChannel类

public NioServerSocketChannel() {
    // 创建一个Socket连接,传递给了一个参数的构造函数
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}

// 创建了一个服务端Socket连接
private static ServerSocketChannel newSocket(SelectorProvider provider) {
    try {
        // 使用JDK的SelectorProvider,开启了一个SocketChannel
        return provider.openServerSocketChannel();
    } catch (IOException e) {
        throw new ChannelException(
                "Failed to open a server socket.", e);
    }
}

public NioServerSocketChannel(ServerSocketChannel channel) {
        // 创建好的SocketChannel传递父类构造函数,同时Accpet事件也传递给了父类,后面会用到
        super(null, channel, SelectionKey.OP_ACCEPT);
        config = new NioServerSocketChannelConfig(this, javaChannel().socket());
    }

到此可知,Netty的Channel中维护着一个JDK的SocketChannel,所以Netty的Channel和JDK的Channel关系是1:1。

我们知道Nio是非阻塞的,来看看什么时候配置?
一直点super(...)下去,直到:

## AbstractNioChannel类

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    super(parent);
    this.ch = ch;
    // 客户端监听OP_READ事件,服务端监听OP_ACCEPT事件,后面会用到
    this.readInterestOp = readInterestOp;
    try {
        // 客户端和服务端的SocketChannel都需要配置非阻塞
        ch.configureBlocking(false);
    } catch (IOException e) {
        try {
            ch.close();
        } catch (IOException e2) {
            logger.warn(
                        "Failed to close a partially initialized socket.", e2);
        }

        throw new ChannelException("Failed to enter non-blocking mode.", e);
    }
}

Channel何时被创建的?

  • 对于NioSocketChannel来说,它是在Bootstrap的connect(...)时被创建的。
  • 对于NioServerSocketChannel来说,它是在ServerBootstrap的bind(...)时被创建的。

以服务端的NioServerSocketChannel来研究何时被创建的,客户端NioSocketChannel创建过程差不多。

来看ServerBootstrap的bind(...)方法源码:

## AbstractBootstrap类

public ChannelFuture bind(int inetPort) {
    // 服务端SocketChannel绑定监听端口,格式:0.0.0.0:Port
    return bind(new InetSocketAddress(inetPort));
}

一直点下去,会跟到doBind(...)方法:

## AbstractBootstrap类

private ChannelFuture doBind(final SocketAddress localAddress) {
    // 对channel进行初始化和注册操作
    final ChannelFuture regFuture = initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
        return regFuture;
    }

    ......
}

来看下initAndRegister(...)方法:

## AbstractBootstrap类

final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        // 创建一个NioServerSocketChannel实例
        channel = channelFactory.newChannel();
        // 初始化channel配置
        init(channel);
    } catch (Throwable t) {
        if (channel != null) {
            channel.unsafe().closeForcibly();
            return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
        }
        return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
    }
    // 服务端channel注册到bossGroup线程池,由bossGroup线程池来处理accept事件
    ChannelFuture regFuture = config().group().register(channel);
    if (regFuture.cause() != null) {
        if (channel.isRegistered()) {
            channel.close();
        } else {
            channel.unsafe().closeForcibly();
        }
    }
    return regFuture;
}

到此,我们知道了服务端的Channel是在AbstractBootstrap类的initAndRegister()方法中创建的

总结

image

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值