一、Netty基础组件介绍
netty程序demo:
public class NettyServerDemo {
private final Integer serverPort;
ServerBootstrap serverBootstrap = new ServerBootstrap();
public NettyDiscardServer(Integer port){
serverPort = port;
}
public void runServer(){
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workGroup = new NioEventLoopGroup();
try{
serverBootstrap.group(bossGroup,workGroup)
.channel(NioServerSocketChannel.class)
.localAddress(serverPort)
.option(ChannelOption.SO_KEEPALIVE,true)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyDiscardHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind().sync();
ChannelFuture closeFuture = channelFuture.channel().closeFuture();
closeFuture.sync();
}catch (Exception e){
e.printStackTrace();
}finally {
workGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
new NettyServerDemo (9999).runServer();
}
}
1、Reactor反应器模式中的IO事件处理流程
流程图:
第一步:通道注册
第二步:查询选择,不断的轮训,查询选择器中的IO事件
第三步:事件分发,分发到handler
第四步:handler处理,真正的io操作和业务处理。
2、Channel通道组件
常见通道:
NioSocketChannel : 异步非阻塞的TCP Socket传输通道
NioServerSocketChannel:异步非阻塞的TCP Socket服务端监听通道
NioDatagramChannel: 异步非阻塞的UDP传输通道
NioSctpChannel :异步非阻塞的Sctp传输通道
NioSctpServerChannel :异步非阻塞的Sctp服务端监听通道
OioSocketChannel:同步阻塞式TCP Socket传输通道
OioServerSocketChannel:同步阻塞式TCP Socket服务监听通道
OioDatagramChannel:同步阻塞式UDP传输通道
OioSctpChannel:同步阻塞式Sctp传输通道
OioSctpServerChannel:同步阻塞式Sctp服务端监听通道
3、Reactor反应器
一个反应器(SubReactor子反应器)会负责一个事件处理线程,不断轮询,通过Selector选择器不断的查询注册过的IO事件。找到IO事件,分发给handler处理。
Netty的反应器类:NioEventLoop
两个重要属性:
selector 和volatile的thread,这个thread 负责selector选择器IO事件的轮询。
图:
一个NioEventLoop对应多个Channel管道。
4、Handler处理器
NioEventLoop内的选择器,查询事件,对事件进行分发(dispatch),事件分发的目标就是Netty自己的Handler处理器。
handler分两类:
入站处理器(ChannelInboundHandler):负责读,从上到下。默认实现ChannelInboundHandlerAdapter
出站处理器(ChannelOutboundHandler):负责写,从下到上。默认实现ChannelOutboundHandlerAdapter
图:
两者都是继承ChannelHandler。
5、Nettty的流水线
ChannelPipeline(通道流水线) 绑定通道和handler的关系,串在一起,形成双线链表。
入站处理器可以截断。
出站处理器不可以,会报异常。
图:
###6、BootStrap启动类
完成客户端和服务端组件的组装以及Netty程序的初始化。
图:
父子通道:
EventLoopGroup(事件循环线程组):
socket描述符分为两类:连接监听类型,传输数据类型。
在Netty中,有接收关系的NioServerSocketChannel和NioSocketChannel 叫做父子通道。
NioServerSocketChannel负责连接监听和接收,叫父通道。
对应于每一个接收到的NioSocketChannel传输类通道,叫做子通道。
7、EventLoopGroup线程组
EventLoopGroup线程组 由多个EventLoop组成。是一个多线程版本的反应器。其中的NioEventLoop线程对应一个子反应器(SubReactor)。
构造参数指定EventLoop数量,内部构造多个线程和多个EventLoop子反应器,进行多线程的IO事件和分发。默认是最大可用cpu的2倍。
Netty程序中有两个反应器:一个负责新连接的监听和接受的EventLoopGroup线程组,查询父通道的IO事件。另一个EventLoopGroup线程组负责所有子通道的IO事件,并执行Handler处理器中的业务处理。
8、Bootstrap启动流程
.1、创建反应器线程组,并赋值给ServerBootstrap启动器实例。
//负责连接监听IO事件
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
//负责IO事件和Handler业务处理
EventLoopGroup workGroup = new NioEventLoopGroup();
//绑定
serverBootstrap.group(bossGroup,workGroup)
2、设置通道的IO类型
serverBootstrap.channel(NioServerSocketChannel.class)
3、设置监听端口
serverBootstrap.localAddress(serverPort)
4、设置传输通道的配置选项
serverBootstrap.option(ChannelOption.SO_KEEPALIVE,true)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
给父通道设置选项,要是给子通道配置用childOption。
5、装配子通道的ChannelPipeline流水线。
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyDiscardHandler());
}
});
initChannel方法在子通道创建后会被执行,向子通道添加业务处理器。
为什么不给父通道装配流水线?
因为父通道NioServerSocketChannel是连接接受通道,业务比较固定。如果需要,可以使用handler方法装配。
6、绑定服务器新连接的监听端口
ChannelFuture channelFuture = serverBootstrap.bind().sync();
7、自我阻塞知道通道阻塞
ChannelFuture closeFuture = channelFuture.channel().closeFuture();
8、关闭EventLoopGroup
orkGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
9、测试入站处理器的方法执行时机:
InHandlerDemo类继承ChannelInboundHandlerAdapter
public class InHandlerDemo extends ChannelInboundHandlerAdapter {
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("handlerAdded() 被调用");
super.handlerAdded(ctx);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelRegistered() 被调用");
super.channelRegistered(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive() 被调用");
super.channelActive(ctx);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("channelRead() 被调用");
super.channelRead(ctx, msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelReadComplete() 被调用");
super.channelReadComplete(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelInactive() 被调用");
super.channelInactive(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelUnregistered() 被调用");
super.channelUnregistered(ctx);
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("handlerRemoved() 被调用");
super.handlerRemoved(ctx);
}
}
测试类
public class InHandlerDemoTest {
public static void main(String[] args) throws InterruptedException {
InHandlerDemo inHandlerDemo = new InHandlerDemo();
ChannelInitializer<EmbeddedChannel> channelInitializer = new ChannelInitializer<EmbeddedChannel>() {
@Override
protected void initChannel(EmbeddedChannel ch) throws Exception {
ch.pipeline().addLast(inHandlerDemo);
}
};
EmbeddedChannel embeddedChannel = new EmbeddedChannel(channelInitializer);
ByteBuf buffer = Unpooled.buffer();
buffer.writeInt(1);
embeddedChannel.writeInbound(buffer);
embeddedChannel.flush();
embeddedChannel.writeInbound(buffer);
embeddedChannel.flush();
embeddedChannel.close();
TimeUnit.SECONDS.sleep(10000);
}
}
输出结果: