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()方法中创建的。
网友评论