Netty的Bootstrap组件
Bootstrap主要用于配置客户端和服务端的核心引导类,简化客户端和服务端的初始化流程。netty的启动器有两个,一个是客户端Bootstrap,一个是服务端ServerBootstrap:
AbstractBootstrap的方法:
| 方法 | 说明 |
|---|---|
| group | 设置用于处理所有事件的EventLoopGroup |
| channel | 指定服务端或客户端的 |
| option | 设置 Channel 参数 |
| bind | 绑定端口 |
| channelchannelFactory | 如果引导没有指定 Channel,那么可以指定 ChannelFactory 来创建 Channel |
| localAddress | 指定 Channel 需要绑定的本地地址,如果不指定,则将由系统随机分配一个地址 |
| remoteAddress | 设置 Channel 需要连接的远程地址 |
| attr | 指定新创建的 Channel 的属性值 |
| handler | 设置添加到 ChannelPipeline 中的 ChannelHandler |
| connect | 连接到远程主机,返回 ChannelFuture,用于连接完成的回调 |
| register | 创建一个 Channel,并注册到 Eventloop |
一、设置线程组
调用 group() 可以设置线程组,该线程组其实就是 Reactor 的线程组,我们知道 Netty 是基于 Reactor 模式的,group() 就是设置 Reactor 模式的线程组,Reactor 模式,线程组有两个:
- BossGroup:服务器连接监听线程组,该线程组专门用来处理客户端的连接请求.
- WorkGroup:工作线程组,即业务处理线程组,用来处理每一条连接的数据收发的线程组.
ServerBootstrap 提供了两个 group() 方法用来设置线程组:
// 这里只配置了一个线程组,也就是 BossGroup 和 WorkGroup 共用一个线程组
public ServerBootstrap group(EventLoopGroup group) {
return this.group(group, group);
}
// 设置 BossGroup 和 WorkGroup
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
super.group(parentGroup);
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
} else {
this.childGroup = (EventLoopGroup)ObjectUtil.checkNotNull(childGroup, "childGroup");
return this;
}
}二、设置Channel 类型
在 NIO 中 Channel 是通信的根本,我们收发数据都是基于 Channel 来实现的,对于 Netty 来说 Channel 也是它通信的通道,不过 Netty 不仅仅只支持 NIO 模式,还有 OIO 。调用 channel() 方法即可设置通道的 IO 类型。Netty 支持的 IO 类型有如下几种:
| 类型 | 异步/同步 | 端 | 协议 |
|---|---|---|---|
| NioSocketChannel | 异步 | 客户端 | TCP |
| NioServerSocketChannel | 异步 | 服务端 | TCP |
| NioSctpChannel | 异步 | 客户端 | STCP |
| NioSctpServerChannel | 异步 | 服务端 | STCP |
| OioSocketChannel | 同步 | 客户端 | TCP |
| OioServerSocketChannel | 同步 | 服务端 | TCP |
| OioSctpChanne | 同步 | 客户端 | STCP |
| OioSctpServerChannel | 同步 | 服务端 | STCP |
| NioDatagramChannel | 异步 | 客户端/服务端 | UDP |
| OioDatagramChanne | 同步 | 客户端/服务端 | UDP |
从上面可以看出,Netty 不仅仅只支持 TCP 协议,还支持 UDP 、STCP 协议,同时每种协议都有 NIO 和 OIO 模式,从 Netty 支持的通道类型就可以看出,Netty 功能有多么强大了。
// 服务端示例
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(new NioEventLoopGroup());
serverBootstrap.channel(NioServerSocketChannel.class);
……….
// 客户端示例
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(new NioEventLoopGroup());
bootstrap.channel(NioSocketChannel.class);
………三、配置option参数
调用 option() 可以设置 Channel 相关的参数,其实 ServerBootstrap 还有一个 childOption() 方法。两个方法的区别是:
option():是给 parent Channel 设置参数的childOption():是给 child Channel 设置参数的。
parent Channel 和child Channel 的区别,我们从设置 EventLoopGroup的时候就可以看出group(EventLoopGroup parentGroup, EventLoopGroup childGroup)Reactor 模式的线程组有两个,parent Channel 是处理客户端的连接请求,child Channel 处理的读写操作。
可以设置的参数比较多,之类列几个常见的:ChannelOption.CONNECT_TIMEOUT_MILLIS:客户端建立连接时,如果超过指定的时间仍未连接,则抛出 timeout 异常。ChannelOption.SO_KEEPALIVE:是否开启 TCP 底层心跳机制,true 表示开启。ChannelOption.TCP_NODELAY:是否启用 Nagle 算法,true 表示开启。开启可能会对消息的实时性有影响,因为为了提升效率, Nagle 算法会将一些较小的数据包收集后再进行发送,这样就会造成我们的消息有延迟。所以如果实时性要求高的话,一般不建议开启。ChannelOption.SO_RCVBUF:设置接收缓冲区的大小ChannelOption.SO_SNDBUF:设置发送缓冲区的大小,一般 SO_RCVBUF 和 SO_SNDBUF 不建议手动设置,因为操作系统会根据当前占用,进行自动的调整。
其他参数,就不一一介绍了,有兴趣的小伙伴可以自行研究, Netty 调优部分会对这些字段进行详细讲解的。
四,配置childHandler参数
ServerBoostrap 提供了 childHandler() 方法设置 ChannelHandler,ChannelHandler主要作用是处理一次读写操作,所以ChannelHandler 有两种:
- ChannelInboundHandler: 处理读入 IO 请求,如StringDecoder。
- ChannelOutboundHandler:处理写出 IO 请求,如StringEncoder。
通常我们通过ChannelInitializer 类的 initChannel()方法,在该方法中我们通过 ChannelPipeline 把多个ChannelHandler流水线的组装成一个处理请求的流水线。
当读请求进来时,传播链从 head 出发,依次经过 InboundHandlerA,InboundHandlerB,InboundHandlerC,最后在 Tail 终止。
当写请求进来时,则相反是传播链从 Tail 出发,依次经过 OutboundHandlerA,OutboundHandlerB,OutboundHandlerC,最后在 Head 终止。