6.1.1 Channel 简介
在Netty 中,Channel 是一个Socket 的抽象,它为用户提供了关于Socket 状态(是否是连接还是断开)以及对Socket
的读写等操作。每当Netty 建立了一个连接后, 都创建一个对应的Channel 实例。
除了TCP 协议以外,Netty 还支持很多其他的连接协议, 并且每种协议还有NIO(非阻塞IO)和OIO(Old-IO, 即传统的
阻塞IO)版本的区别。不同协议不同的阻塞类型的连接都有不同的Channel 类型与之对应下面是一些常用的Channel
6.1.2 NioSocketChannel 的创建
客户端的代码片段:
public class ChatClient {
public ChatClient connect(int port,String host,final String nickName){
EventLoopGroup group = new NioEventLoopGroup();//指定EventLoopGroup
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer
@Override
protected void initChannel(SocketChannel ch) throws Exception {
...
}
});
//发起同步连接操作
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
channelFuture.channel().closeFuture().sync();
}
catch (InterruptedException e) {
e.printStackTrace();
}finally{
//关闭,释放线程资源
group.shutdownGracefully();
}return this;
}
public static void main(String[] args) {
new ChatClient().connect(8080, "localhost","Tom 老师");
}
从上面的客户端代码虽然简单, 但是却展示了Netty 客户端初始化时所需的所有内容:
1、EventLoopGroup:不论是服务器端还是客户端, 都必须指定EventLoopGroup。在这个例子中, 指定了
NioEventLoopGroup, 表示一个NIO 的EventLoopGroup。
2、ChannelType: 指定Channel 的类型。因为是客户端,因此使用了NioSocketChannel。
3、Handler: 设置处理数据的Handler。
NioSocketChannel 的类层次结构如下:
回到我们在客户端连接代码的初始化Bootstrap 中调用了一个channel()方法,传入的参数是NioSocketChannel.class,
在这个方法中其实就是初始化了一个ReflectiveChannelFactory 的对象:
public B channel(Class extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new ReflectiveChannelFactory
}
而ReflectiveChannelFactory 实现了ChannelFactory 接口, 它提供了唯一的方法, 即newChannel()方法,
ChannelFactory, 顾名思义, 就是创建Channel 的工厂类。进入到ReflectiveChannelFactory 的newChannel()方法中。
根据上面代码的提示,我们就可以得出:
1、Bootstrap 中的ChannelFactory 实现类是ReflectiveChannelFactory。
2、通过channel()方法创建的Channel 具体类型是NioSocketChannel。
Channel 的实例化过程其实就是调用ChannelFactory 的newChannel()方法,而实例化的Channel 具体类型又是和初
始化Bootstrap 时传入的channel()方法的参数相关。因此对于客户端的Bootstrap 而言,创建的Channel 实例就是
NioSocketChannel。
6.1.3 客户端Channel 的初始化
前面我们已经知道了如何设置一个Channel 的类型,并且了解到Channel 是通过ChannelFactory 的newChannel()方
法来实例化的, 那么ChannelFactory 的newChannel()方法在哪里调用呢?继续跟踪, 我们发现其调用链如下:
在AbstractBootstrap 的initAndRegister()中调用了ChannelFactory()的newChannel()来创建一个NioSocketChannel
的实例,其源码如下:
final ChannelFuture initAndRegister() {
// 去掉非关键代码
Channel channel = channelFactory.newChannel();
init(channel);
ChannelFuture regFuture = config().group().register(channel);
// 去掉非关键代码
return regFuture;
}
在newChannel()方法中,利用反射机制调用类对象的newInstance()方法来创建一个新的Channel 实例,相当于调用
NioSocketChannel 的默认构造器。NioSocketChannel 的默认构造器代码如下:
public NioSocketChannel() {
this(DEFAULT_SELECTOR_PROVIDER);
}